Points: refactor E57Reader

This commit is contained in:
wmayer
2022-12-22 19:14:38 +01:00
parent eb31752998
commit 3e576c3bca

View File

@@ -1310,6 +1310,368 @@ void PcdReader::readBinary(bool transpose,
// ----------------------------------------------------------------------------
namespace {
class E57ReaderImp
{
public:
E57ReaderImp(const std::string& filename, bool color, bool state, double distance)
: imfi(filename, "r")
, useColor{color}
, checkState{state}
, minDistance{distance}
{
}
void read()
{
e57::StructureNode root = imfi.root();
if (root.isDefined("data3D")) {
e57::VectorNode data3D(root.get("data3D"));
readData3D(data3D);
}
}
std::vector<App::Color> getColors() const
{
return colors;
}
const PointKernel& getPoints() const
{
return points;
}
private:
void readData3D(const e57::VectorNode& data3D)
{
for (int child = 0; child < data3D.childCount(); ++child) {
e57::StructureNode scan_data(data3D.get(child));
Base::Placement plm;
bool hasPlacement = getPlacement(scan_data, plm);
e57::CompressedVectorNode cvn(scan_data.get("points"));
e57::StructureNode prototype(cvn.prototype());
Proto proto = readProto(prototype);
processProto(cvn, proto, hasPlacement, plm);
}
}
struct Proto
{
bool inty = false;
bool inv_state = false;
unsigned cnt_xyz = 0;
unsigned cnt_rgb = 0;
std::vector<double> xData;
std::vector<double> yData;
std::vector<double> zData;
std::vector<unsigned> redData;
std::vector<unsigned> greenData;
std::vector<unsigned> blueData;
std::vector<double> intensity;
std::vector<int64_t> state;
std::vector<int64_t> nil;
std::vector<e57::SourceDestBuffer> sdb;
};
Proto readProto(const e57::StructureNode& prototype)
{
Proto proto;
resizeArrays(proto);
for (int i = 0; i < prototype.childCount(); ++i) {
e57::Node node(prototype.get(i));
if ((node.type() == e57::E57_FLOAT) || (node.type() == e57::E57_SCALED_INTEGER)) {
if (readCartesian(node, proto)) {
}
else if (readItensity(node, proto)) {
}
else {
readOther(node, proto);
}
}
else if (node.type() == e57::E57_INTEGER) {
if (readColor(node, proto)) {
}
else if (readCartesianInvalidState(node, proto)) {
}
else {
readOther(node, proto);
}
}
}
return proto;
}
bool readCartesian(const e57::Node& node, Proto& proto)
{
if (node.elementName() == "cartesianX") {
proto.cnt_xyz++;
proto.sdb.emplace_back(
imfi
, node.elementName()
, proto.xData.data()
, buf_size
, true
, true
);
return true;
}
else if (node.elementName() == "cartesianY") {
proto.cnt_xyz++;
proto.sdb.emplace_back(
imfi
, node.elementName()
, proto.yData.data()
, buf_size
, true
, true
);
return true;
}
else if (node.elementName() == "cartesianZ") {
proto.cnt_xyz++;
proto.sdb.emplace_back(
imfi
, node.elementName()
, proto.zData.data()
, buf_size
, true
, true
);
return true;
}
return false;
}
bool readCartesianInvalidState(const e57::Node& node, Proto& proto)
{
if (node.elementName() == "cartesianInvalidState") {
proto.inv_state = true;
proto.sdb.emplace_back(
imfi
, node.elementName()
, proto.state.data()
, buf_size
, true
, true
);
return true;
}
return false;
}
bool readColor(const e57::Node& node, Proto& proto)
{
if (node.elementName() == "colorRed") {
proto.cnt_rgb++;
proto.sdb.emplace_back(
imfi
, node.elementName()
, proto.redData.data()
, buf_size
, true
, true
);
return true;
}
else if (node.elementName() == "colorGreen") {
proto.cnt_rgb++;
proto.sdb.emplace_back(
imfi
, node.elementName()
, proto.greenData.data()
, buf_size
, true
, true
);
return true;
}
else if (node.elementName() == "colorBlue") {
proto.cnt_rgb++;
proto.sdb.emplace_back(
imfi
, node.elementName()
, proto.blueData.data()
, buf_size
, true
, true
);
return true;
}
return false;
}
bool readItensity(const e57::Node& node, Proto& proto)
{
if (node.elementName() == "intensity") {
proto.inty = true;
proto.sdb.emplace_back(
imfi
, node.elementName()
, proto.intensity.data()
, buf_size
, true
, true
);
return true;
}
return false;
}
void readOther(const e57::Node& node, Proto& proto)
{
proto.sdb.emplace_back(
imfi
, node.elementName()
, proto.nil.data()
, buf_size
, true
, true
);
}
void processProto(e57::CompressedVectorNode& cvn, const Proto& proto, bool hasPlacement, const Base::Placement& plm)
{
if (proto.cnt_xyz != 3) {
throw Base::BadFormatError("Missing channels xyz");
}
unsigned count;
unsigned cnt_pts = 0;
Base::Vector3d pt, last;
e57::CompressedVectorReader cvr(cvn.reader(proto.sdb));
bool hasColor = (proto.cnt_rgb == 3) && useColor;
bool hasState = proto.inv_state && checkState;
bool filter = false;
while ((count = cvr.read())) {
for (size_t i = 0; i < count; ++i) {
filter = false;
if (hasState) {
if (proto.state[i] != 0) { filter = true; }
}
pt = getCoord(proto, i, hasPlacement, plm);
if ((!filter) && (cnt_pts > 0)) {
if (Base::Distance(last, pt) < minDistance) {
filter = true;
}
}
if (!filter) {
cnt_pts++;
points.push_back(pt);
last = pt;
if (hasColor) {
colors.push_back(getColor(proto, i));
}
}
}
}
}
Base::Vector3d getCoord(const Proto& proto, size_t index, bool hasPlacement, const Base::Placement& plm) const
{
Base::Vector3d pt;
pt.x = proto.xData[index];
pt.y = proto.yData[index];
pt.z = proto.zData[index];
if (hasPlacement) {
plm.multVec(pt, pt);
}
return pt;
}
App::Color getColor(const Proto& proto, size_t index) const
{
App::Color c;
c.r = static_cast<float>(proto.redData[index]) / 255.0f;
c.g = static_cast<float>(proto.greenData[index]) / 255.0f;
c.b = static_cast<float>(proto.blueData[index]) / 255.0f;
if (proto.inty) {
c.a = proto.intensity[index];
}
return c;
}
void resizeArrays(Proto& proto)
{
proto.xData.resize(buf_size);
proto.yData.resize(buf_size);
proto.zData.resize(buf_size);
proto.redData.resize(buf_size);
proto.greenData.resize(buf_size);
proto.blueData.resize(buf_size);
proto.intensity.resize(buf_size);
proto.state.resize(buf_size);
proto.nil.resize(buf_size);
}
bool getPlacement(const e57::StructureNode& scan_data, Base::Placement& plm) const
{
bool hasPlacement{false};
if (scan_data.isDefined("pose")) {
e57::StructureNode pose(scan_data.get("pose"));
if (pose.isDefined("rotation")) {
e57::StructureNode rotNode(pose.get("rotation"));
double quaternion[4];
quaternion[0] = e57::FloatNode(rotNode.get("x")).value();
quaternion[1] = e57::FloatNode(rotNode.get("y")).value();
quaternion[2] = e57::FloatNode(rotNode.get("z")).value();
quaternion[3] = e57::FloatNode(rotNode.get("w")).value();
Base::Rotation rotate(quaternion);
plm.setRotation(rotate);
hasPlacement = true;
}
if (pose.isDefined("translation")) {
Base::Vector3d move;
e57::StructureNode transNode(pose.get("translation"));
move.x = e57::FloatNode(transNode.get("x")).value();
move.y = e57::FloatNode(transNode.get("y")).value();
move.z = e57::FloatNode(transNode.get("z")).value();
plm.setPosition(move);
hasPlacement = true;
}
}
return hasPlacement;
}
private:
e57::ImageFile imfi;
bool useColor;
bool checkState;
double minDistance;
const size_t buf_size = 1024;
std::vector<App::Color> colors;
PointKernel points;
};
}
E57Reader::E57Reader(const bool& Color, const bool& State, const float& Distance)
{
useColor = Color;
@@ -1324,237 +1686,16 @@ E57Reader::~E57Reader()
void E57Reader::read(const std::string& filename)
{
try {
// read file
e57::ImageFile imfi(filename, "r");
e57::StructureNode root = imfi.root();
if (root.isDefined("data3D")) {
e57::VectorNode data3D(root.get("data3D"));
for (int child = 0; child < data3D.childCount(); ++child) {
e57::StructureNode scan_data(data3D.get(child));
Base::Placement plm;
bool hasPlacement{false};
if (scan_data.isDefined("pose")) {
e57::StructureNode pose(scan_data.get("pose"));
if (pose.isDefined("rotation")) {
e57::StructureNode rotNode(pose.get("rotation"));
double quaternion[4];
quaternion[0] = e57::FloatNode(rotNode.get("x")).value();
quaternion[1] = e57::FloatNode(rotNode.get("y")).value();
quaternion[2] = e57::FloatNode(rotNode.get("z")).value();
quaternion[3] = e57::FloatNode(rotNode.get("w")).value();
Base::Rotation rotate(quaternion);
plm.setRotation(rotate);
hasPlacement = true;
}
if (pose.isDefined("translation")) {
Base::Vector3d move;
e57::StructureNode transNode(pose.get("translation"));
move.x = e57::FloatNode(transNode.get("x")).value();
move.y = e57::FloatNode(transNode.get("y")).value();
move.z = e57::FloatNode(transNode.get("z")).value();
plm.setPosition(move);
hasPlacement = true;
}
}
e57::CompressedVectorNode cvn(scan_data.get("points"));
e57::StructureNode prototype(cvn.prototype());
// create buffers for the compressed vector reader
const size_t buf_size = 1024;
double xyz[buf_size * 3];
double intensity[buf_size];
int64_t state[buf_size];
unsigned rgb[buf_size * 3];
int64_t nil[buf_size];
// check the channels which are needed
unsigned ptr_xyz[3];
unsigned ptr_rgb[3];
bool inty = false;
bool inv_state = false;
unsigned cnt_xyz = 0;
unsigned cnt_rgb = 0;
std::vector<e57::SourceDestBuffer> sdb;
for (int i = 0; i < prototype.childCount(); ++i) {
e57::Node n(prototype.get(i));
if ((n.type() == e57::E57_FLOAT) || (n.type() == e57::E57_SCALED_INTEGER)) {
if (n.elementName() == "cartesianX") {
ptr_xyz[0] = cnt_xyz++;
sdb.emplace_back(
imfi
, n.elementName()
, &(xyz[0])
, buf_size
, true
, true
);
}
else if (n.elementName() == "cartesianY") {
ptr_xyz[1] = cnt_xyz++;
sdb.emplace_back(
imfi
, n.elementName()
, &(xyz[buf_size])
, buf_size
, true
, true
);
}
else if (n.elementName() == "cartesianZ") {
ptr_xyz[2] = cnt_xyz++;
sdb.emplace_back(
imfi
, n.elementName()
, &(xyz[2 * buf_size])
, buf_size
, true
, true
);
}
else if (n.elementName() == "intensity") {
inty = true;
sdb.emplace_back(
imfi
, n.elementName()
, &(intensity[0])
, buf_size
, true
, true
);
}
else {
sdb.emplace_back(
imfi
, n.elementName()
, &(nil[0])
, buf_size
, true
, true
);
}
}
else if (n.type() == e57::E57_INTEGER) {
if (n.elementName() == "colorRed") {
ptr_rgb[0] = cnt_rgb++;
sdb.emplace_back(
imfi
, n.elementName()
, &(rgb[0])
, buf_size
, true
, true
);
}
else if (n.elementName() == "colorGreen") {
ptr_rgb[1] = cnt_rgb++;
sdb.emplace_back(
imfi
, n.elementName()
, &(rgb[buf_size])
, buf_size
, true
, true
);
}
else if (n.elementName() == "colorBlue") {
ptr_rgb[2] = cnt_rgb++;
sdb.emplace_back(
imfi
, n.elementName()
, &(rgb[2 * buf_size])
, buf_size
, true
, true
);
}
else if (n.elementName() == "cartesianInvalidState") {
inv_state = true;
sdb.emplace_back(
imfi
, n.elementName()
, &(state[0])
, buf_size
, true
, true
);
}
else {
sdb.emplace_back(
imfi
, n.elementName()
, &(nil[0])
, buf_size
, true
, true
);
}
}
}
// read the data
if (cnt_xyz == 3) {
unsigned count;
unsigned cnt_pts = 0;
Base::Vector3d pt, last;
e57::CompressedVectorReader cvr(cvn.reader(sdb));
bool hasColor = (cnt_rgb == 3) && useColor;
bool hasState = inv_state && checkState;
bool filter = false;
while ((count = cvr.read())) {
for (size_t i = 0; i < count; ++i) {
filter = false;
if (hasState) {
if (state[i] != 0) { filter = true; }
}
pt.x = xyz[ptr_xyz[0] * buf_size + i];
pt.y = xyz[ptr_xyz[1] * buf_size + i];
pt.z = xyz[ptr_xyz[2] * buf_size + i];
if (hasPlacement) {
plm.multVec(pt, pt);
}
if ((!filter) && (cnt_pts > 0)) {
if (Base::Distance(last, pt) < minDistance) {
filter = true;
}
}
if (!filter) {
cnt_pts++;
points.push_back(pt);
last = pt;
if (hasColor) {
App::Color c;
c.r = static_cast<float>(rgb[ptr_rgb[0] * buf_size + i]) / 255.0f;
c.g = static_cast<float>(rgb[ptr_rgb[1] * buf_size + i]) / 255.0f;
c.b = static_cast<float>(rgb[ptr_rgb[2] * buf_size + i]) / 255.0f;
if (inty) { c.a = intensity[i]; }
colors.push_back(c);
}
}
}
}
}
else {
Base::Console().Error("Missing channels xyz.");
}
}
}
E57ReaderImp reader(filename, useColor, checkState, minDistance);
reader.read();
points = reader.getPoints();
colors = reader.getColors();
}
catch (const Base::BadFormatError&) {
throw;
}
catch (...) {
points.clear();
throw Base::BadFormatError("E57");
throw Base::BadFormatError("Reading E57 file failed");
}
}