From a5e6edff8743d920691a9e8fa36d5939342d63f9 Mon Sep 17 00:00:00 2001 From: wmayer Date: Fri, 4 Mar 2016 14:48:26 +0100 Subject: [PATCH] + support of export of points to pcd and ply format --- src/Mod/Mesh/App/AppMeshPy.cpp | 3 - src/Mod/Points/App/AppPointsPy.cpp | 93 +++++++- src/Mod/Points/App/PointsAlgos.cpp | 353 +++++++++++++++++++++++++++++ src/Mod/Points/App/PointsAlgos.h | 47 ++++ src/Mod/Points/Init.py | 4 + 5 files changed, 495 insertions(+), 5 deletions(-) diff --git a/src/Mod/Mesh/App/AppMeshPy.cpp b/src/Mod/Mesh/App/AppMeshPy.cpp index cab5d68b3..a21127b07 100644 --- a/src/Mod/Mesh/App/AppMeshPy.cpp +++ b/src/Mod/Mesh/App/AppMeshPy.cpp @@ -67,9 +67,6 @@ public: add_varargs_method("insert",&Module::importer, "insert(string|mesh,[string]) -- Load or insert a mesh into the given or active document." ); - add_varargs_method("insert",&Module::importer, - "insert(string|mesh,[string]) -- Load or insert a mesh into the given or active document." - ); add_varargs_method("export",&Module::exporter, "export(list,string,[tolerance]) -- Export a list of objects into a single file. tolerance is in mm\n" "and specifies the maximum acceptable deviation between the specified objects and the exported mesh." diff --git a/src/Mod/Points/App/AppPointsPy.cpp b/src/Mod/Points/App/AppPointsPy.cpp index fc42d2a01..af70468eb 100644 --- a/src/Mod/Points/App/AppPointsPy.cpp +++ b/src/Mod/Points/App/AppPointsPy.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include "Points.h" @@ -59,7 +60,9 @@ public: { add_varargs_method("open",&Module::open ); - add_varargs_method("insert",&Module::insert + add_varargs_method("insert",&Module::importer + ); + add_varargs_method("export",&Module::exporter ); add_varargs_method("show",&Module::show ); @@ -172,7 +175,7 @@ private: return Py::None(); } - Py::Object insert(const Py::Tuple& args) + Py::Object importer(const Py::Tuple& args) { char* Name; const char* DocName; @@ -279,6 +282,92 @@ private: return Py::None(); } + Py::Object exporter(const Py::Tuple& args) + { + PyObject *object; + char *Name; + + if (!PyArg_ParseTuple(args.ptr(), "Oet", &object, "utf-8", &Name)) + throw Py::Exception(); + + std::string encodedName = std::string(Name); + PyMem_Free(Name); + + Base::FileInfo file(encodedName); + + // extract ending + if (file.extension().empty()) + throw Py::RuntimeError("No file extension"); + + Py::Sequence list(object); + Base::Type pointsId = Base::Type::fromName("Points::Feature"); + for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { + PyObject* item = (*it).ptr(); + if (PyObject_TypeCheck(item, &(App::DocumentObjectPy::Type))) { + App::DocumentObject* obj = static_cast(item)->getDocumentObjectPtr(); + if (obj->getTypeId().isDerivedFrom(pointsId)) { + + Points::Feature* fea = static_cast(obj); + const PointKernel& kernel = fea->Points.getValue(); + std::auto_ptr writer; + if (file.hasExtension("asc")) { + writer.reset(new AscWriter(kernel)); + } +#ifdef HAVE_PCL_IO + else if (file.hasExtension("ply")) { + writer.reset(new PlyWriter(kernel)); + } + else if (file.hasExtension("pcd")) { + writer.reset(new PcdWriter(kernel)); + } +#endif + else { + throw Py::RuntimeError("Unsupported file extension"); + } + + // get additional properties if there + App::PropertyInteger* width = dynamic_cast + (fea->getPropertyByName("Width")); + if (width) { + writer->setWidth(width->getValue()); + } + App::PropertyInteger* height = dynamic_cast + (fea->getPropertyByName("Height")); + if (height) { + writer->setHeight(height->getValue()); + } + // get gray values + Points::PropertyGreyValueList* grey = dynamic_cast + (fea->getPropertyByName("Intensity")); + if (grey) { + writer->setIntensities(grey->getValues()); + } + // get colors + App::PropertyColorList* col = dynamic_cast + (fea->getPropertyByName("Color")); + if (col) { + writer->setColors(col->getValues()); + } + // get normals + Points::PropertyNormalList* nor = dynamic_cast + (fea->getPropertyByName("Normal")); + if (nor) { + writer->setNormals(nor->getValues()); + } + + writer->write(encodedName); + + break; + } + else { + Base::Console().Message("'%s' is not a point object, export will be ignored.\n", obj->Label.getValue()); + } + } + } + + return Py::None(); + } + Py::Object show(const Py::Tuple& args) { PyObject *pcObj; diff --git a/src/Mod/Points/App/PointsAlgos.cpp b/src/Mod/Points/App/PointsAlgos.cpp index bc139b829..65b5bf48f 100644 --- a/src/Mod/Points/App/PointsAlgos.cpp +++ b/src/Mod/Points/App/PointsAlgos.cpp @@ -46,6 +46,7 @@ #include #include +#include using namespace Points; @@ -436,3 +437,355 @@ void PcdReader::read(const std::string& filename) } #endif + +// ---------------------------------------------------------------------------- + +Writer::Writer(const PointKernel& p) : points(p) +{ + width = p.size(); + height = 1; +} + +Writer::~Writer() +{ +} + +void Writer::setIntensities(const std::vector& i) +{ + intensity = i; +} + +void Writer::setColors(const std::vector& c) +{ + colors = c; +} + +void Writer::setNormals(const std::vector& n) +{ + normals = n; +} + +void Writer::setWidth(int w) +{ + width = w; +} + +void Writer::setHeight(int h) +{ + height = h; +} + +// ---------------------------------------------------------------------------- + +AscWriter::AscWriter(const PointKernel& p) : Writer(p) +{ +} + +AscWriter::~AscWriter() +{ +} + +void AscWriter::write(const std::string& filename) +{ + points.save(filename.c_str()); +} + +// ---------------------------------------------------------------------------- + +#ifdef HAVE_PCL_IO +PlyWriter::PlyWriter(const PointKernel& p) : Writer(p) +{ +} + +PlyWriter::~PlyWriter() +{ +} + +void PlyWriter::write(const std::string& filename) +{ + bool hasIntensity = (intensity.size() == points.size()); + bool hasColors = (colors.size() == points.size()); + bool hasNormals = (normals.size() == points.size()); + + if (hasNormals && hasColors) { + pcl::PointCloud cloud_out; + cloud_out.reserve(points.size()); + + const std::vector& pts = points.getBasicPoints(); + std::size_t num_points = pts.size(); + for (std::size_t index=0; index(filename, cloud_out); + } + else if (hasNormals && hasIntensity) { + pcl::PointCloud cloud_out; + cloud_out.reserve(points.size()); + + const std::vector& pts = points.getBasicPoints(); + std::size_t num_points = pts.size(); + for (std::size_t index=0; index(filename, cloud_out); + } + else if (hasColors) { + pcl::PointCloud cloud_out; + cloud_out.reserve(points.size()); + + const std::vector& pts = points.getBasicPoints(); + std::size_t num_points = pts.size(); + for (std::size_t index=0; index(filename, cloud_out); + } + else if (hasIntensity) { + pcl::PointCloud cloud_out; + cloud_out.reserve(points.size()); + + const std::vector& pts = points.getBasicPoints(); + std::size_t num_points = pts.size(); + for (std::size_t index=0; index(filename, cloud_out); + } + else if (hasNormals) { + pcl::PointCloud cloud_out; + cloud_out.reserve(points.size()); + + const std::vector& pts = points.getBasicPoints(); + std::size_t num_points = pts.size(); + for (std::size_t index=0; index(filename, cloud_out); + } + else { + pcl::PointCloud cloud_out; + cloud_out.reserve(points.size()); + for (Points::PointKernel::const_iterator it = points.begin(); it != points.end(); ++it) { + if (!boost::math::isnan(it->x) && !boost::math::isnan(it->y) && !boost::math::isnan(it->z)) { + cloud_out.push_back(pcl::PointXYZ(it->x, it->y, it->z)); + } + } + + pcl::io::savePLYFile(filename, cloud_out); + } +} + +// ---------------------------------------------------------------------------- + +PcdWriter::PcdWriter(const PointKernel& p) : Writer(p) +{ +} + +PcdWriter::~PcdWriter() +{ +} + +void PcdWriter::write(const std::string& filename) +{ + bool hasIntensity = (intensity.size() == points.size()); + bool hasColors = (colors.size() == points.size()); + bool hasNormals = (normals.size() == points.size()); + + if (hasNormals && hasColors) { + pcl::PointCloud cloud_out; + cloud_out.reserve(points.size()); + + const std::vector& pts = points.getBasicPoints(); + std::size_t num_points = pts.size(); + for (std::size_t index=0; index(filename, cloud_out); + } + else if (hasNormals && hasIntensity) { + pcl::PointCloud cloud_out; + cloud_out.reserve(points.size()); + + const std::vector& pts = points.getBasicPoints(); + std::size_t num_points = pts.size(); + for (std::size_t index=0; index(filename, cloud_out); + } + else if (hasColors) { + pcl::PointCloud cloud_out; + cloud_out.reserve(points.size()); + + const std::vector& pts = points.getBasicPoints(); + std::size_t num_points = pts.size(); + for (std::size_t index=0; index(filename, cloud_out); + } + else if (hasIntensity) { + pcl::PointCloud cloud_out; + cloud_out.reserve(points.size()); + + const std::vector& pts = points.getBasicPoints(); + std::size_t num_points = pts.size(); + for (std::size_t index=0; index(filename, cloud_out); + } + else if (hasNormals) { + pcl::PointCloud cloud_out; + cloud_out.reserve(points.size()); + + const std::vector& pts = points.getBasicPoints(); + std::size_t num_points = pts.size(); + for (std::size_t index=0; index(filename, cloud_out); + } + else { + pcl::PointCloud cloud_out; + cloud_out.reserve(points.size()); + for (Points::PointKernel::const_iterator it = points.begin(); it != points.end(); ++it) { + cloud_out.push_back(pcl::PointXYZ(it->x, it->y, it->z)); + } + + cloud_out.width = width; + cloud_out.height = height; + + pcl::io::savePCDFile(filename, cloud_out); + } +} +#endif diff --git a/src/Mod/Points/App/PointsAlgos.h b/src/Mod/Points/App/PointsAlgos.h index a6843e290..820a7db8b 100644 --- a/src/Mod/Points/App/PointsAlgos.h +++ b/src/Mod/Points/App/PointsAlgos.h @@ -97,6 +97,53 @@ public: }; #endif +class Writer +{ +public: + Writer(const PointKernel&); + virtual ~Writer(); + virtual void write(const std::string& filename) = 0; + + void setIntensities(const std::vector&); + void setColors(const std::vector&); + void setNormals(const std::vector&); + void setWidth(int); + void setHeight(int); + +protected: + const PointKernel& points; + std::vector intensity; + std::vector colors; + std::vector normals; + int width, height; +}; + +class AscWriter : public Writer +{ +public: + AscWriter(const PointKernel&); + ~AscWriter(); + void write(const std::string& filename); +}; + +#ifdef HAVE_PCL_IO +class PlyWriter : public Writer +{ +public: + PlyWriter(const PointKernel&); + ~PlyWriter(); + void write(const std::string& filename); +}; + +class PcdWriter : public Writer +{ +public: + PcdWriter(const PointKernel&); + ~PcdWriter(); + void write(const std::string& filename); +}; +#endif + } // namespace Points diff --git a/src/Mod/Points/Init.py b/src/Mod/Points/Init.py index 8eeb50226..3285ce602 100644 --- a/src/Mod/Points/Init.py +++ b/src/Mod/Points/Init.py @@ -31,3 +31,7 @@ FreeCAD.addImportType("Point formats (*.asc)","Points") FreeCAD.addImportType("PLY points (*.ply)","Points") FreeCAD.addImportType("PCD points (*.pcd)","Points") + +FreeCAD.addExportType("Point formats (*.asc)","Points") +FreeCAD.addExportType("PLY points (*.ply)","Points") +FreeCAD.addExportType("PCD points (*.pcd)","Points")