Skip to content
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
15 changes: 13 additions & 2 deletions include/ezc3d/Parameter.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ class EZC3D_VISIBILITY ezc3d::ParametersNS::GroupNS::Parameter {
/// \param groupIdx Index of the group that this particular parameter is in
/// \param dataStartPositionToFill The position in the file where the data
/// start (special case for POINT:DATA_START and ROTATION:DATA_START
/// parameters) \param dataStartType The type of data start (-1 no data start,
/// 0 points, 1 rotations)
/// parameters)
/// \param dataStartType The type of data start (-1 no data start, 0 points,
/// 1 rotations)
///
/// Write the parameter and its values to a file
///
Expand Down Expand Up @@ -191,6 +192,16 @@ class EZC3D_VISIBILITY ezc3d::ParametersNS::GroupNS::Parameter {
///
EZC3D_API ezc3d::DATA_TYPE type() const;

///
/// \brief Force a cast on the type for the data, effectively changing its
/// type. This can only be done for switching between int and float. Other
/// types casting will raise an exception. Obviously, this is cause loss of
/// data if the original type is float and the new type is int and decimal are
/// present. No checks are done in this regard.
/// \param type The type to set for the data
///
EZC3D_API void staticCastType(ezc3d::DATA_TYPE newType);

///
/// \brief Return the vector of values of the parameter
/// \return The vector of values of the parameter
Expand Down
26 changes: 26 additions & 0 deletions src/Parameter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,32 @@ ezc3d::DATA_TYPE ezc3d::ParametersNS::GroupNS::Parameter::type() const {
return _data_type;
}

void ezc3d::ParametersNS::GroupNS::Parameter::staticCastType(
ezc3d::DATA_TYPE newType) {
if (newType == _data_type)
return;

if ((newType != DATA_TYPE::INT && newType != DATA_TYPE::FLOAT) ||
(_data_type != DATA_TYPE::INT && _data_type != DATA_TYPE::FLOAT)) {
throw std::invalid_argument(
"staticCastType can only be used to switch between INT and FLOAT");
}

if (newType == DATA_TYPE::INT) {
_data_type = newType;
_param_data_int.clear();
for (unsigned int i = 0; i < _param_data_double.size(); ++i)
_param_data_int.push_back(static_cast<int>(_param_data_double[i]));
_param_data_double.clear();
} else if (newType == DATA_TYPE::FLOAT) {
_data_type = newType;
_param_data_double.clear();
for (unsigned int i = 0; i < _param_data_int.size(); ++i)
_param_data_double.push_back(static_cast<double>(_param_data_int[i]));
_param_data_int.clear();
}
}

void ezc3d::ParametersNS::GroupNS::Parameter::set(int data) {
set(std::vector<int>() = {data});
}
Expand Down
68 changes: 46 additions & 22 deletions src/ezc3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ ezc3d::c3d::c3d(const std::string &filePath, const Options &options)

// Read all the section
_header = std::make_shared<ezc3d::Header>(*this, stream);
_parameters = std::make_shared<ezc3d::ParametersNS::Parameters>(*this, stream);
_parameters =
std::make_shared<ezc3d::ParametersNS::Parameters>(*this, stream);

// header may be inconsistent with the parameters, so it must be
// update to make sure sizes are consistent
Expand Down Expand Up @@ -163,24 +164,24 @@ void ezc3d::c3d::writeDataStart(

if (dataStartPosition.hasHeaderPointDataStart()) {
f.seekg(dataStartPosition.headerPointDataStart());
int nBlocksToNext = int(dataStartPosition.pointDataStart()) / 512 +
1; // DATA_START is 1-based
// DATA_START is 1-based
int nBlocksToNext = int(dataStartPosition.pointDataStart()) / 512 + 1;
f.write(reinterpret_cast<const char *>(&nBlocksToNext),
dataStartPosition.headerPointDataStartSize());
}

if (dataStartPosition.hasParameterPointDataStart()) {
f.seekg(dataStartPosition.parameterPointDataStart());
int nBlocksToNext = int(dataStartPosition.pointDataStart()) / 512 +
1; // DATA_START is 1-based
// DATA_START is 1-based
int nBlocksToNext = int(dataStartPosition.pointDataStart()) / 512 + 1;
f.write(reinterpret_cast<const char *>(&nBlocksToNext),
dataStartPosition.parameterPointDataStartSize());
}

if (dataStartPosition.hasParameterRotationsDataStart()) {
f.seekg(dataStartPosition.parameterRotationsDataStart());
int nBlocksToNext = int(dataStartPosition.rotationsDataStart()) / 512 +
1; // DATA_START is 1-based
// DATA_START is 1-based
int nBlocksToNext = int(dataStartPosition.rotationsDataStart()) / 512 + 1;
f.write(reinterpret_cast<const char *>(&nBlocksToNext),
dataStartPosition.parameterRotationsDataStartSize());
}
Expand Down Expand Up @@ -792,21 +793,20 @@ void ezc3d::c3d::updateHeader() {
data().frame(0).analogs().nbSubframes() != 0) {
if (data().frame(0).analogs().nbSubframes() != header().nbAnalogByFrame())
_header->nbAnalogByFrame(data().frame(0).analogs().nbSubframes());
} else if (
static_cast<size_t>(pointRate) != 0
&& static_cast<size_t>(analog.parameter("RATE").valuesAsDouble()[0] / pointRate) != header().nbAnalogByFrame()
) {
if (header().nbAnalogByFrame() == 1 && parameters().isGroup("SHADOW")) {
// The SHADOW company is not following the standard so they did not
// set analog rate ezc3d automatically sets it to zero which results
// in a discrepancy
ezc3d::ParametersNS::GroupNS::Parameter &analogNonConst =
_parameters->group("ANALOG").parameter("RATE");
analogNonConst.set(static_cast<float>(header().nbAnalogByFrame()));
} else {
_header->nbAnalogByFrame(static_cast<size_t>(
analog.parameter("RATE").valuesAsDouble()[0] / pointRate));
}
} else if (static_cast<size_t>(pointRate) != 0 &&
static_cast<size_t>(analog.parameter("RATE").valuesAsDouble()[0] /
pointRate) != header().nbAnalogByFrame()) {
if (header().nbAnalogByFrame() == 1 && parameters().isGroup("SHADOW")) {
// The SHADOW company is not following the standard so they did not
// set analog rate ezc3d automatically sets it to zero which results
// in a discrepancy
ezc3d::ParametersNS::GroupNS::Parameter &analogNonConst =
_parameters->group("ANALOG").parameter("RATE");
analogNonConst.set(static_cast<float>(header().nbAnalogByFrame()));
} else {
_header->nbAnalogByFrame(static_cast<size_t>(
analog.parameter("RATE").valuesAsDouble()[0] / pointRate));
}
}

if (static_cast<size_t>(analog.parameter("USED").valuesAsInt()[0]) !=
Expand Down Expand Up @@ -1044,6 +1044,30 @@ void ezc3d::c3d::updateParameters(const std::vector<std::string> &newPoints,
}
}

// Deal with ACTUAL_START_FIELD and ACTUAL_END_FIELD from VICON, if they are
// present
bool isVicon = parameters().isGroup("MANUFACTURER") &&
parameters().group("MANUFACTURER").isParameter("COMPANY") &&
parameters()
.group("MANUFACTURER")
.parameter("COMPANY")
.valuesAsString()
.at(0)
.find("Vicon") != std::string::npos;
if (isVicon &&
parameters().group("TRIAL").isParameter("ACTUAL_START_FIELD")) {
// Make sure "ACTUAL_START_FIELD" is of type INT
_parameters->group("TRIAL")
.parameter("ACTUAL_START_FIELD")
.staticCastType(ezc3d::DATA_TYPE::INT);
}
if (isVicon && parameters().group("TRIAL").isParameter("ACTUAL_END_FIELD")) {
// Make sure "ACTUAL_END_FIELD" is of type INT
_parameters->group("TRIAL")
.parameter("ACTUAL_END_FIELD")
.staticCastType(ezc3d::DATA_TYPE::INT);
}

// Adjust some ROTATION parameters
if (_parameters->isGroup("ROTATION")) {
ezc3d::ParametersNS::GroupNS::Group &grpRotation(
Expand Down
80 changes: 80 additions & 0 deletions test/test_ezc3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,86 @@ TEST(parameters, getParametersAsDouble) {
}
}

TEST(parameters, switchType) {
// Do nothing cases
{
ezc3d::ParametersNS::GroupNS::Parameter p;
p.set(std::vector<int>({1, 2, 3}));
EXPECT_EQ(p.type(), ezc3d::INT);
p.staticCastType(ezc3d::INT);
EXPECT_EQ(p.type(), ezc3d::INT);
for (size_t i = 0; i < 3; ++i)
EXPECT_EQ(p.valuesAsInt()[i], static_cast<int>((i + 1)));
}
{
ezc3d::ParametersNS::GroupNS::Parameter p;
p.set(std::vector<double>({1.1, 2.2, 3.3}));
EXPECT_EQ(p.type(), ezc3d::FLOAT);
p.staticCastType(ezc3d::FLOAT);
EXPECT_EQ(p.type(), ezc3d::FLOAT);
for (size_t i = 0; i < 3; ++i)
EXPECT_DOUBLE_AS_FLOAT_EQ(p.valuesAsDouble()[i],
static_cast<double>(i + 1) * 1.1);
}
{
ezc3d::ParametersNS::GroupNS::Parameter p;
p.set(std::vector<std::string>({"a", "b", "c"}));
EXPECT_EQ(p.type(), ezc3d::CHAR);
p.staticCastType(ezc3d::CHAR);
EXPECT_EQ(p.type(), ezc3d::CHAR);
for (size_t i = 0; i < 3; ++i)
EXPECT_STREQ(p.valuesAsString()[i].c_str(),
std::string(1, static_cast<char>('a' + i)).c_str());
}

// To FLOAT
{
ezc3d::ParametersNS::GroupNS::Parameter p;
p.set(std::vector<int>({1, 2, 3}));
EXPECT_EQ(p.type(), ezc3d::INT);
p.staticCastType(ezc3d::FLOAT);
EXPECT_EQ(p.type(), ezc3d::FLOAT);
for (size_t i = 0; i < 3; ++i)
EXPECT_EQ(p.valuesAsDouble()[i], static_cast<int>((i + 1)));
}

// To INT
{
ezc3d::ParametersNS::GroupNS::Parameter p;
p.set(std::vector<double>({1.1, 2.2, 3.3}));
EXPECT_EQ(p.type(), ezc3d::FLOAT);
p.staticCastType(ezc3d::INT);
EXPECT_EQ(p.type(), ezc3d::INT);
for (size_t i = 0; i < 3; ++i)
EXPECT_EQ(p.valuesAsInt()[i], static_cast<int>((i + 1)));
}

// Trying to switch to other types should throw an error
{
ezc3d::ParametersNS::GroupNS::Parameter p;
p.set(std::vector<int>({1, 2, 3}));
EXPECT_THROW(p.staticCastType(ezc3d::CHAR), std::invalid_argument);
EXPECT_THROW(p.staticCastType(ezc3d::BYTE), std::invalid_argument);
EXPECT_THROW(p.staticCastType(ezc3d::NO_DATA_TYPE), std::invalid_argument);
}
{
ezc3d::ParametersNS::GroupNS::Parameter p;
p.set(std::vector<double>({1.1, 2.2, 3.3}));
EXPECT_THROW(p.staticCastType(ezc3d::CHAR), std::invalid_argument);
EXPECT_THROW(p.staticCastType(ezc3d::BYTE), std::invalid_argument);
EXPECT_THROW(p.staticCastType(ezc3d::NO_DATA_TYPE), std::invalid_argument);
}

// Trying to switch from other types should throw an error
{
ezc3d::ParametersNS::GroupNS::Parameter p;
p.set(std::vector<std::string>({"a", "b", "c"}));
EXPECT_EQ(p.type(), ezc3d::CHAR);
EXPECT_THROW(p.staticCastType(ezc3d::INT), std::invalid_argument);
EXPECT_THROW(p.staticCastType(ezc3d::FLOAT), std::invalid_argument);
}
}

TEST(c3dModifier, specificParameters) {
// Create an empty c3d
c3dTestStruct new_c3d;
Expand Down
Loading