From 8be69caa60b7812f12f4a59ba67ceee450867903 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud guennebaud Date: Wed, 8 Oct 2008 11:07:53 +0000 Subject: [PATCH] add an Expe's point set file format importer --- src/meshlabplugins/io_expe/import_expe.cpp | 0 src/meshlabplugins/io_expe/import_expe.h | 421 +++++++++++++++++++++ src/meshlabplugins/io_expe/io_expe.cpp | 154 ++++++++ src/meshlabplugins/io_expe/io_expe.h | 48 +++ src/meshlabplugins/io_expe/io_expe.pro | 7 + 5 files changed, 630 insertions(+) create mode 100644 src/meshlabplugins/io_expe/import_expe.cpp create mode 100644 src/meshlabplugins/io_expe/import_expe.h create mode 100644 src/meshlabplugins/io_expe/io_expe.cpp create mode 100644 src/meshlabplugins/io_expe/io_expe.h create mode 100644 src/meshlabplugins/io_expe/io_expe.pro diff --git a/src/meshlabplugins/io_expe/import_expe.cpp b/src/meshlabplugins/io_expe/import_expe.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/src/meshlabplugins/io_expe/import_expe.h b/src/meshlabplugins/io_expe/import_expe.h new file mode 100644 index 000000000..82ab97f9e --- /dev/null +++ b/src/meshlabplugins/io_expe/import_expe.h @@ -0,0 +1,421 @@ +/**************************************************************************** +* VCGLib o o * +* Visual and Computer Graphics Library o o * +* _ O _ * +* Copyright(C) 2004 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +/* This code has been adapted from the OFF importer and Gael's .pts loader from Expe */ + +#ifndef __VCGLIB_IMPORT_EXPE +#define __VCGLIB_IMPORT_EXPE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace vcg +{ +namespace tri +{ +namespace io +{ + +static const char * Header_EPSB01 = "[Expe/PointSet/Binary/0.1]"; +static const char * Header_EPSB02 = "[Expe/PointSet/Binary/0.2]"; +static const char * Header_EPSA02 = "[Expe/PointSet/Ascii/0.2]"; + +// /** \addtogroup */ +// /* @{ */ +/** +This class encapsulate a filter for importing Expes's .pts point sets. +*/ +template +class ImporterExpePTS +{ + public: + + typedef typename MESH_TYPE::VertexType VertexType; + typedef typename MESH_TYPE::VertexIterator VertexIterator; + typedef typename MESH_TYPE::VertexPointer VertexPointer; + typedef typename MESH_TYPE::CoordType CoordType; + typedef typename MESH_TYPE::ScalarType ScalarType; + + enum ExpeCodes {NoError=0, CantOpen, InvalidFile, UnsupportedVersion}; + + struct Options + { + Options() + : onlyMaskFlag(false) + {} + bool onlyMaskFlag; + }; + + struct FileProperty + { + FileProperty(QByteArray _name, uint _size) + : name(_name), size(_size) + {} + QByteArray name; // name of the property + uint size; // size in byte (binary mode) + bool hasProperty; // true if the target mesh has the property + }; + typedef std::vector FileProperties; + + + static uint getSizeOfPropertyType(const QByteArray& type) + { + uint size = 0; + if(type=="r32" || type=="ui32" || type=="i32") + { + size = 4; + } + else if(type=="r16" || type=="ui16" || type=="i16") + { + size = 2; + } + else if(type=="ui8" || type=="i8") + { + size = 1; + } + return size; + } + + /*! + * Standard call for knowing the meaning of an error code + * \param message_code The code returned by Open + * \return The string describing the error code + */ + static const char* ErrorMsg(int message_code) + { + static const char* error_msg[] = + { + "No errors", "Can't open file", "Invalid file", "Unsupported version" + }; + + if(message_code>4 || message_code<0) + return "Unknown error"; + else + return error_msg[message_code]; + }; + + /** + * Load only the properties of the 3D objects. + * + * \param filename the name of the file to read from + * \param loadmask the mask which encodes the properties + * \return the operation result + */ + static bool LoadMask(const char *filename, int &loadmask) + { + // To obtain the loading mask all the file must be parsed + // to distinguish between per-vertex and per-face color attribute. + loadmask=0; + MESH_TYPE dummyMesh; + return (Open(dummyMesh, filename, loadmask,0,true)==NoError); + } + + static int Open(MESH_TYPE &mesh, const char *filename, CallBackPos *cb=0) + { + int loadmask; + return Open(mesh,filename,loadmask,cb); + } + + /*! + * Standard call for reading a mesh. + * + * \param mesh the destination mesh + * \param filename the name of the file to read from + * \return the operation result + */ + static int Open(MESH_TYPE &mesh, const char *filename, int &loadmask, + CallBackPos *cb=0, bool onlyMaskFlag=false) + { + Options opt; + opt.onlyMaskFlag = onlyMaskFlag; + return Open(mesh, filename, loadmask, opt, cb); + } + + static int Open(MESH_TYPE &mesh, const char *filename, int &loadmask, + const Options& options, CallBackPos *cb=0) + { + QFile device(filename); + if ( (!device.open(QFile::ReadOnly)) ) + return CantOpen; + + QTextStream stream(&device); + + // check the header file and version + QString tmp; + QByteArray propertyName, command; + QByteArray dataFormat; + int propertySize, nofPoints = -1; + stream >> tmp; + + QStringList header = tmp.split(QRegExp("[\\[/\\]]"),QString::SkipEmptyParts); + if(header.size()!=4) + return InvalidFile; + + if(header[0] != "Expe") + return InvalidFile; + + if(header[1] != "PointSet") + return InvalidFile; + + if(header[2]!="Ascii" && header[2]!="Binary") + return InvalidFile; + + if(header[3]!="0.1" && header[3]!="0.2") + return UnsupportedVersion; + + loadmask = 0; + FileProperties fileProperties; + int pointSize = 0; + + stream >> command; + while(command!="data") + { + if(command=="property") + { + if(header[3]=="0.1") + { + stream >> propertyName >> propertySize; + } + else if(header[3]=="0.2") + { + QByteArray propertyType; + // name / nof atomic element / type of an atomic element + stream >> propertyName >> propertySize >> propertyType; + propertySize *= getSizeOfPropertyType(propertyType); + } + + fileProperties.push_back(FileProperty(propertyName,propertySize)); + + if(propertyName=="position") + { + loadmask |= Mask::IOM_VERTCOORD; + fileProperties.back().hasProperty = true; + } + else if(propertyName=="radius") + { + // TODO +// loadmask |= Mask::IOM_VERTRADIUS; +// fileProperties.back().hasProperty = mesh.HasVertRadius(); + } + else if(propertyName=="normal") + { + loadmask |= Mask::IOM_VERTNORMAL; + fileProperties.back().hasProperty = tri::HasPerVertexNormal(mesh); + } + else if(propertyName=="color") + { + loadmask |= Mask::IOM_VERTCOLOR; + fileProperties.back().hasProperty = tri::HasPerVertexColor(mesh); + } + pointSize += propertySize; + } + else if(command=="nofpoints") + { + stream >> nofPoints; + } + else + { + std::cerr << "Unknow command " << command.data() << " (skip)" << "\n"; + } + stream >> command; + } + + if (options.onlyMaskFlag) + return 0; + + if (pointSize<0) + return InvalidFile; + + qint64 streamPos = stream.pos(); + stream.setDevice(0); + device.reset(); + device.seek(streamPos); + + if(header[2]=="Binary") + return appendBinaryData(mesh, nofPoints, fileProperties, pointSize, device); + else if(header[2]=="Ascii") + return appendAsciiData(mesh, nofPoints, fileProperties, device); + + return 0; + } // end Open + + template + static bool parse_vector(const QString& str, VectorType& v) + { + bool ok = true; + QRegExp xtrimming("^.*([-\\d].*\\d).*$"); + xtrimming.indexIn(str); + QString trimmed = xtrimming.cap(1); + QList elements = trimmed.split(QRegExp("[ \t]+|[ \t]*,[ \t]*")); + int expectedSize = v.size(); + if (elements.size() != expectedSize) + return false; + for (uint k=0 ; k v(3); + std::vector c(4); + QStringList line; + uint i=0; + VertexIterator v_iter = Allocator::AddVertices(mesh, nofPoints); + while(iP()[j] = v[j]; + } + else if(fileProperties[k].name=="normal") + { + if (!parse_vector(line[k], v)) + { + std::cerr << "Error parsing normal " << line[k].toLocal8Bit().data() << "\n"; + return InvalidFile; + } + for (int j=0; j<3; ++j) + v_iter->N()[j] = v[j]; + } + else if(fileProperties[k].name=="radius") + { + bool ok = true; + // TODO v_iter->R() = line[k].toFloat(&ok); + if (!ok) + { + std::cerr << "Error parsing radius " << line[k].toLocal8Bit().data() << "\n"; + return InvalidFile; + } + } + else if(fileProperties[k].name=="color") + { + if (!parse_vector(line[k], c)) + { + std::cerr << "Error parsing color " << line[k].toLocal8Bit().data() << "\n"; + return InvalidFile; + } + vcg::Color4f color(c[0],c[1],c[2],c[3]); + (*v_iter).C().Import(color); + } + else + { + std::cerr << "unsupported property " << fileProperties[k].name.data() << "\n"; + } + } + } + ++v_iter; + } + else if(line.size()!=0) + { + std::cerr << "\tInvalid line : " << line[0].toLocal8Bit().data() << "... (skip)\n"; + } + } + return 0; + } + + static int appendBinaryData(MESH_TYPE& mesh, uint nofPoints, const FileProperties& fileProperties, + int pointSize, QIODevice& device) + { + QDataStream stream(&device); + std::vector data(pointSize); + + // skip \n + stream.skipRawData(1); + + std::vector v(3); + VertexIterator v_iter = Allocator::AddVertices(mesh, nofPoints); + for(uint i=0 ; i(&data[0]), pointSize); + int b = 0; // offset in byte + for(uint k=0 ; k(&data[b]); + for (int j=0; j<3; ++j) + v_iter->P()[j] = p[j]; + } + else if(fileProperties[k].name=="normal") + { + float* n = reinterpret_cast(&data[b]); + for (int j=0; j<3; ++j) + v_iter->N()[j] = n[j]; + } + else if(fileProperties[k].name=="radius") + { + // TODO + } + else if(fileProperties[k].name=="color") + { + vcg::Color4b color(data[b],data[b+1],data[b+2],data[b+3]); + (*v_iter).C().Import(color); + } + else + { + std::cerr << "unsupported property " << fileProperties[k].name.data() << "\n"; + } + } + b += fileProperties[k].size; + } + ++v_iter; + } + return 0; + } + + protected: + +}; +// /*! @} */ + +} //namespace io +} //namespace tri +} // namespace vcg + +#endif //__VCGLIB_IMPORT_EXPE diff --git a/src/meshlabplugins/io_expe/io_expe.cpp b/src/meshlabplugins/io_expe/io_expe.cpp new file mode 100644 index 000000000..9ab4b7519 --- /dev/null +++ b/src/meshlabplugins/io_expe/io_expe.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +* MeshLab o o * +* An extendible mesh processor o o * +* _ O _ * +* Copyright(C) 2005, 2006 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +#include +#include + +#include "io_expe.h" + +#include +#include +#include +#include + +#include "import_expe.h" +// #include "export_expe.h" + +#include + +using namespace std; +using namespace vcg; + + +// initialize importing parameters +// void ExpeIOPlugin::initPreOpenParameter(const QString &formatName, const QString &filename, FilterParameterSet &parlst) +// { +// parlst.addBool("pointsonly",false,"Keep only points","Just import points, without triangulation"); +// parlst.addBool("flipfaces",false,"Flip all faces","Flip the orientation of all the triangles"); +// } + + +bool ExpeIOPlugin::open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask, const FilterParameterSet &parlst, CallBackPos *cb, QWidget *parent) +{ + // initializing mask + mask = 0; + + // initializing progress bar status + if (cb != NULL) (*cb)(0, "Loading..."); + + QString errorMsgFormat = "Error encountered while loading file:\n\"%1\"\n\nError details: %2"; + QString error_2MsgFormat = "Error encountered while loading file:\n\"%1\"\n\n File with more than a mesh.\n Load only the first!"; + + string filename = QFile::encodeName(fileName).constData (); + + bool normalsUpdated = false; + + if ( (formatName.toLower() == tr("pts")) || (formatName.toLower() == tr("apts")) ) + { + int loadMask; + if (!vcg::tri::io::ImporterExpePTS::LoadMask(filename.c_str(),loadMask)) + return false; + m.Enable(loadMask); + + int result = vcg::tri::io::ImporterExpePTS::Open(m.cm, filename.c_str(), mask, cb); + if (result != 0) + { + QMessageBox::warning(parent, tr("Expe Point Set Opening Error"), + errorMsgFormat.arg(fileName, vcg::tri::io::ImporterExpePTS::ErrorMsg(result))); + return false; + } + } + + vcg::tri::UpdateBounding::Box(m.cm); // updates bounding box + + if (cb != NULL) + (*cb)(99, "Done"); + + return true; +} + +bool ExpeIOPlugin::save(const QString &formatName, const QString &fileName, MeshModel &m, const int mask, const FilterParameterSet &, vcg::CallBackPos *cb, QWidget *parent) +{ + QString errorMsgFormat = "Error encountered while exporting file %1:\n%2"; + string filename = QFile::encodeName(fileName).constData (); + string ex = formatName.toUtf8().data(); + +// if( formatName.toUpper() == tr("GTS") ) +// { +// int result = vcg::tri::io::ExporterGTS::Save(m.cm,filename.c_str(),mask); +// if(result!=0) +// { +// QMessageBox::warning(parent, tr("Saving Error"), errorMsgFormat.arg(fileName, vcg::tri::io::ExporterGTS::ErrorMsg(result))); +// return false; +// } +// return true; +// } + assert(0); // unknown format + return false; +} + +/* + returns the list of the file's type which can be imported +*/ +QList ExpeIOPlugin::importFormats() const +{ + QList formatList; + formatList << Format("Expe's point set (binary)" ,tr("pts")); + formatList << Format("Expe's point set (ascii)" ,tr("apts")); + formatList << Format("XYZ point with normal" ,tr("xyz")); + return formatList; +} + +/* + returns the list of the file's type which can be exported +*/ +QList ExpeIOPlugin::exportFormats() const +{ + QList formatList; +// formatList << Format("Expe's point set (binary)" ,tr("pts")); +// formatList << Format("Expe's point set (ascii)" ,tr("apts")); +// formatList << Format("XYZ point with normal" ,tr("xyz")); + return formatList; +} + +/* + returns the mask on the basis of the file's type. + otherwise it returns 0 if the file format is unknown +*/ +void ExpeIOPlugin::GetExportMaskCapability(QString &format, int &capability, int &defaultBits) const +{ +// if(format.toLower() == tr("apts")){capability=defaultBits= vcg::tri::io::ExporterExpeAPTS::GetExportMaskCapability();} +// if(format.toLower() == tr("pts")){capability=defaultBits= vcg::tri::io::ExporterExpePTS::GetExportMaskCapability();} + return; +} + +const PluginInfo &ExpeIOPlugin::Info() +{ + static PluginInfo ai; + ai.Date=tr("Oct 2008"); + ai.Version = tr("0.1"); + ai.Author = ("Gael Guennebaud"); + return ai; +} + +Q_EXPORT_PLUGIN(ExpeIOPlugin) diff --git a/src/meshlabplugins/io_expe/io_expe.h b/src/meshlabplugins/io_expe/io_expe.h new file mode 100644 index 000000000..475b669dd --- /dev/null +++ b/src/meshlabplugins/io_expe/io_expe.h @@ -0,0 +1,48 @@ +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2005 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ + +#ifndef IO_EXPE_PLUGIN_H +#define IO_EXPE_PLUGIN_H + +#include + +#include +#include + +class ExpeIOPlugin : public QObject, public MeshIOInterface +{ + Q_OBJECT + Q_INTERFACES(MeshIOInterface) + + +public: + QList importFormats() const; + QList exportFormats() const; + virtual const PluginInfo &Info(); + virtual void GetExportMaskCapability(QString &format, int &capability, int &defaultBits) const; +// void initPreOpenParameter(const QString &/*format*/, const QString &/*fileName*/, FilterParameterSet & /*par*/); + bool open(const QString &formatName, const QString &fileName, MeshModel &m, int& mask, const FilterParameterSet &, vcg::CallBackPos *cb=0, QWidget *parent=0); + bool save(const QString &formatName, const QString &fileName, MeshModel &m, const int mask, const FilterParameterSet &, vcg::CallBackPos *cb, QWidget *parent); +}; + +#endif diff --git a/src/meshlabplugins/io_expe/io_expe.pro b/src/meshlabplugins/io_expe/io_expe.pro new file mode 100644 index 000000000..2f5b852b1 --- /dev/null +++ b/src/meshlabplugins/io_expe/io_expe.pro @@ -0,0 +1,7 @@ +include (../../shared.pri) + +HEADERS = io_expe.h + +SOURCES = io_expe.cpp + +TARGET = io_expe