Allow all filetypes supported by meshlab to be opened with meshlabserver

VisualSFM (and some other formats) output *.nvm, *.rd.out projects that
meshlab can easily import and use, but the logic for this never made it
into meshlabserver. I pretty much just wholesale copied/adapted the
existing code from meshlab into meshlabserver, allowing any supported
project to be imported like any other mlb file.
This commit is contained in:
Chelsea Jaggi 2020-06-23 16:22:21 -07:00
parent b51f9e01ac
commit 74f55f5273
9 changed files with 280 additions and 41 deletions

View File

@ -30,7 +30,6 @@
#include "saveSnapshotDialog.h"
#include "ui_aboutDialog.h"
#include "savemaskexporter.h"
#include "alnParser.h"
#include <exception>
#include "ml_default_decorators.h"
@ -44,6 +43,7 @@
#include "../common/meshlabdocumentxml.h"
#include "../common/meshlabdocumentbundler.h"
#include "../common/mlapplication.h"
#include "../common/alnParser.h"
#include "../common/filterscript.h"
#include "../common/mlexception.h"

View File

@ -21,7 +21,7 @@ HEADERS = plymc.h \
trivial_walker.h \
tri_edge_collapse_mc.h \
simplemeshprovider.h \
../../meshlab/alnParser.h
../../common/alnParser.h
!CONFIG(system_glew): INCLUDEPATH *= ../../code/lib/glew/include

View File

@ -28,6 +28,8 @@
#include <common/pluginmanager.h>
#include <common/filterscript.h>
#include <common/meshlabdocumentxml.h>
#include <common/meshlabdocumentbundler.h>
#include <common/alnParser.h>
#include <common/mlexception.h>
#include <common/filterparameter.h>
#include <wrap/qt/qt_thread_safe_memory_info.h>
@ -242,40 +244,282 @@ public:
return true;
}
bool openProject(MeshDocument& md,const QString& filename)
bool loadMesh(const QString& fileName, MeshIOInterface *pCurrentIOPlugin, MeshModel* mm, int& mask,RichParameterSet* prePar, const Matrix44m &mtr, MeshDocument* md, FILE* fp = stdout)
{
QDir curDir = QDir::current();
QFileInfo fi(filename);
std::map<int, MLRenderingData> tmp;
bool opened = MeshDocumentFromXML(md,fi.absoluteFilePath(), fi.suffix().toLower() == "mlb",tmp);
if (!opened)
if (mm == NULL)
return false;
QDir::setCurrent(fi.absolutePath());
//WARNING! I'm not putting inside MeshDocumentFromXML function because I'm too scared of what can happen inside MeshLab code....
md.setFileName(fi.absoluteFilePath());
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
for (int i=0; i<md.meshList.size(); i++)
QFileInfo fi(fileName);
QString extension = fi.suffix();
if(!fi.exists())
{
if (md.meshList[i] != NULL)
QString errorMsgFormat = "Unable to open file:\n\"%1\"\n\nError details: file %1 does not exist.";
fprintf(fp, "Meshlab Opening Error: %s", errorMsgFormat.arg(fileName).toStdString().c_str());
return false;
}
if(!fi.isReadable())
{
QString errorMsgFormat = "Unable to open file:\n\"%1\"\n\nError details: file %1 is not readable.";
fprintf(fp, "Meshlab Opening Error: %s", errorMsgFormat.arg(fileName).toStdString().c_str());
return false;
}
// the original directory path before we switch it
QString origDir = QDir::current().path();
// this change of dir is needed for subsequent textures/materials loading
QDir::setCurrent(fi.absoluteDir().absolutePath());
// Adjust the file name after changing the directory
QString fileNameSansDir = fi.fileName();
// retrieving corresponding IO plugin
if (pCurrentIOPlugin == 0)
{
QString errorMsgFormat = "Error encountered while opening file:\n\"%1\"\n\nError details: The \"%2\" file extension does not correspond to any supported format.";
fprintf(fp, "Opening Error: %s", errorMsgFormat.arg(fileName, extension).toStdString().c_str());
QDir::setCurrent(origDir); // undo the change of directory before leaving
return false;
}
md->setBusy(true);
pCurrentIOPlugin->setLog(&md->Log);
if (!pCurrentIOPlugin->open(extension, fileNameSansDir, *mm ,mask,*prePar))
{
fprintf(fp, "Opening Failure: %s", (QString("While opening: '%1'\n\n").arg(fileName)+pCurrentIOPlugin->errorMsg()).toStdString().c_str()); // text+
pCurrentIOPlugin->clearErrorString();
md->setBusy(false);
QDir::setCurrent(origDir); // undo the change of directory before leaving
return false;
}
//std::cout << "Opened mesh: in " << tm.elapsed() << " secs\n";
// After opening the mesh lets ask to the io plugin if this format
// requires some optional, or userdriven post-opening processing.
// and in that case ask for the required parameters and then
// ask to the plugin to perform that processing
//RichParameterSet par;
//pCurrentIOPlugin->initOpenParameter(extension, *mm, par);
//pCurrentIOPlugin->applyOpenParameter(extension, *mm, par);
QString err = pCurrentIOPlugin->errorMsg();
if (!err.isEmpty())
{
fprintf(fp, "Opening Problems: %s", (QString("While opening: '%1'\n\n").arg(fileName)+pCurrentIOPlugin->errorMsg()).toStdString().c_str());
pCurrentIOPlugin->clearErrorString();
}
//saveRecentFileList(fileName);
//if (!(mm->cm.textures.empty()))
// updateTexture(mm->id());
// In case of polygonal meshes the normal should be updated accordingly
if( mask & vcg::tri::io::Mask::IOM_BITPOLYGONAL)
{
mm->updateDataMask(MeshModel::MM_POLYGONAL); // just to be sure. Hopefully it should be done in the plugin...
int degNum = vcg::tri::Clean<CMeshO>::RemoveDegenerateFace(mm->cm);
if(degNum)
fprintf(stdout, "Warning model contains %i degenerate faces. Removed them.",degNum);
mm->updateDataMask(MeshModel::MM_FACEFACETOPO);
vcg::tri::UpdateNormal<CMeshO>::PerBitQuadFaceNormalized(mm->cm);
vcg::tri::UpdateNormal<CMeshO>::PerVertexFromCurrentFaceNormal(mm->cm);
} // standard case
else
{
vcg::tri::UpdateNormal<CMeshO>::PerFaceNormalized(mm->cm);
if(!( mask & vcg::tri::io::Mask::IOM_VERTNORMAL) )
vcg::tri::UpdateNormal<CMeshO>::PerVertexAngleWeighted(mm->cm);
}
vcg::tri::UpdateBounding<CMeshO>::Box(mm->cm); // updates bounding box
if(mm->cm.fn==0 && mm->cm.en==0)
{
if(mask & vcg::tri::io::Mask::IOM_VERTNORMAL)
mm->updateDataMask(MeshModel::MM_VERTNORMAL);
}
if(mm->cm.fn==0 && mm->cm.en>0)
{
if (mask & vcg::tri::io::Mask::IOM_VERTNORMAL)
mm->updateDataMask(MeshModel::MM_VERTNORMAL);
}
//updateMenus();
int delVertNum = vcg::tri::Clean<CMeshO>::RemoveDegenerateVertex(mm->cm);
int delFaceNum = vcg::tri::Clean<CMeshO>::RemoveDegenerateFace(mm->cm);
vcg::tri::Allocator<CMeshO>::CompactEveryVector(mm->cm);
if(delVertNum>0 || delFaceNum>0 )
fprintf(fp, "MeshLab Warning: %s", (QString("Warning mesh contains %1 vertices with NAN coords and %2 degenerated faces.\nCorrected.").arg(delVertNum).arg(delFaceNum)).toStdString().c_str() );
mm->cm.Tr = mtr;
//computeRenderingDataOnLoading(mm,isareload, rendOpt);
//updateLayerDialog();
md->setBusy(false);
QDir::setCurrent(origDir); // undo the change of directory before leaving
return true;
}
bool loadMeshWithStandardParams(QString& fullPath, MeshModel* mm, const Matrix44m &mtr = Matrix44m::Identity(), MeshDocument* md = NULL)
{
if ((mm == NULL) || (md == NULL))
return false;
bool ret = false;
if (!mm->isVisible())
{
mm->Clear();
mm->visible = false;
}
else
mm->Clear();
QFileInfo fi(fullPath);
QString extension = fi.suffix();
MeshIOInterface *pCurrentIOPlugin = PM.allKnowInputFormats[extension.toLower()];
if(pCurrentIOPlugin != NULL)
{
RichParameterSet prePar;
pCurrentIOPlugin->initPreOpenParameter(extension, fullPath,prePar);
//prePar = prePar.join(currentGlobalParams);
int mask = 0;
QElapsedTimer t;t.start();
bool open = loadMesh(fullPath,pCurrentIOPlugin,mm,mask,&prePar,mtr, md, stdout);
if(open)
{
QString fullPath = md.meshList[i]->fullName();
md.setBusy(true);
Matrix44m trm = md.meshList[i]->cm.Tr; // save the matrix, because loadMeshClear it...
if (!importMesh(*md.meshList[i],fullPath))
{
md.delMesh(md.meshList[i]);
md.setBusy(false);
QDir::setCurrent(curDir.absolutePath());
return false;
}
else
md.meshList[i]->cm.Tr=trm;
md.setCurrentMesh(md.meshList[i]->id());
md.setBusy(false);
RichParameterSet par;
pCurrentIOPlugin->initOpenParameter(extension, *mm, par);
pCurrentIOPlugin->applyOpenParameter(extension,*mm,par);
ret = true;
}
}
QDir::setCurrent(curDir.absolutePath());
return ret;
}
bool openProject(MeshDocument& md,const QString& fileName,FILE* fp = stdout)
{
//bool visiblelayer = layerDialog->isVisible();
//showLayerDlg(false);
//globrendtoolbar->setEnabled(false);
if (fileName.isEmpty()) return false;
QFileInfo fi(fileName);
//lastUsedDirectory = fi.absoluteDir();
//TODO: move this to main()
if((fi.suffix().toLower()!="aln") && (fi.suffix().toLower()!="mlp") && (fi.suffix().toLower() != "mlb") && (fi.suffix().toLower()!="out") && (fi.suffix().toLower()!="nvm"))
{
//QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unknown project file extension");
fprintf(fp, "Meshlab Opening Error: Unknown project file extension\n");
return false;
}
// Common Part: init a Doc if necessary, and
//bool activeDoc = (bool) !mdiarea->subWindowList().empty() && mdiarea->currentSubWindow();
//bool activeEmpty = activeDoc && md.meshList.empty();
//if (!activeEmpty) newProject(fileName);
md.setFileName(fileName);
//mdiarea->currentSubWindow()->setWindowTitle(fileName);
md.setDocLabel(fileName);
md.setBusy(true);
// this change of dir is needed for subsequent textures/materials loading
QDir::setCurrent(fi.absoluteDir().absolutePath());
//qb->show();
if (QString(fi.suffix()).toLower() == "aln")
{
std::vector<RangeMap> rmv;
int retVal = ALNParser::ParseALN(rmv, qUtf8Printable(fileName));
if(retVal != ALNParser::NoError)
{
//QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open ALN file");
fprintf(fp,"Meshlab Opening Error: Unable to open ALN file\n");
return false;
}
bool openRes=true;
std::vector<RangeMap>::iterator ir;
for(ir=rmv.begin();ir!=rmv.end() && openRes;++ir)
{
QString relativeToProj = fi.absoluteDir().absolutePath() + "/" + (*ir).filename.c_str();
md.addNewMesh(relativeToProj,relativeToProj);
openRes = loadMeshWithStandardParams(relativeToProj,md.mm(),ir->trasformation, &md);
if(!openRes)
md.delMesh(md.mm());
}
}
if (QString(fi.suffix()).toLower() == "mlp" || QString(fi.suffix()).toLower() == "mlb")
{
std::map<int, MLRenderingData> rendOpt;
if (!MeshDocumentFromXML(md, fileName, (QString(fi.suffix()).toLower() == "mlb"), rendOpt))
{
//QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open MeshLab Project file");
fprintf(fp,"Meshlab Opening Error: Unable to open MeshLab Project file\n");
return false;
}
//GLA()->updateMeshSetVisibilities();
for (int i=0; i<md.meshList.size(); i++)
{
QString fullPath = md.meshList[i]->fullName();
//md.setBusy(true);
Matrix44m trm = md.meshList[i]->cm.Tr; // save the matrix, because loadMeshClear it...
if (!loadMeshWithStandardParams(fullPath, md.meshList[i], trm, &md))
md.delMesh(md.meshList[i]);
}
}
////// BUNDLER
if (QString(fi.suffix()).toLower() == "out"){
QString cameras_filename = fileName;
QString image_list_filename;
QString model_filename;
image_list_filename = "list.txt";
if(image_list_filename.isEmpty())
return false;
if(!MeshDocumentFromBundler(md,cameras_filename,image_list_filename,model_filename)){
//QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open OUTs file");
fprintf(fp,"Meshlab Opening Error: Unable to open OUTs file\n");
return false;
}
//WARNING!!!!! i suppose it's not useful anymore but.......
/*GLA()->setColorMode(GLW::CMPerVert);
GLA()->setDrawMode(GLW::DMPoints);*/
/////////////////////////////////////////////////////////
}
//////NVM
if (QString(fi.suffix()).toLower() == "nvm"){
QString cameras_filename = fileName;
QString model_filename;
if(!MeshDocumentFromNvm(md,cameras_filename,model_filename)){
//QMessageBox::critical(this, tr("Meshlab Opening Error"), "Unable to open NVMs file");
fprintf(fp,"Meshlab Opening Error: Unable to open NVMs file\n");
return false;
}
//WARNING!!!!! i suppose it's not useful anymore but.......
/*GLA()->setColorMode(GLW::CMPerVert);
GLA()->setDrawMode(GLW::DMPoints);*/
/////////////////////////////////////////////////////////
}
md.setBusy(false);
//qb->reset();
return true;
}
@ -655,13 +899,7 @@ int main(int argc, char *argv[])
{
QFileInfo finfo(argv[i+1]);
QString inputproject = finfo.absoluteFilePath();
if (finfo.completeSuffix().toLower() != "mlp")
{
fprintf(logfp,"Project %s is not a valid \'mlp\' file format. MeshLabServer application will exit.\n",qUtf8Printable(inputproject));
//system("pause");
exit(-1);
}
bool opened = server.openProject(meshDocument,inputproject);
bool opened = server.openProject(meshDocument,inputproject, logfp);
if (!opened)
{
fprintf(logfp,"MeshLab Project %s has not been correctly opened. MeshLabServer application will exit.\n",qUtf8Printable(inputproject));

View File

@ -10,7 +10,8 @@ meshlabserver [logargs] [args]
where args can be:
-p filename meshlab project (.mlp) to be loaded
-p filename meshlab project (.mlp/.mlb/.aln/.out/.nvm) to
be loaded
-w filename [-x] output meshlab project (.mlp) to be saved.
If -x flag is specified a 3D model meshfile.ext

View File

@ -42,7 +42,7 @@ $Log: meshedit.cpp,v $
#include <vcg/complex/algorithms/clustering.h>
#include <vcg/complex/algorithms/hole.h>
#include <wrap/io_trimesh/export_ply.h>
#include <meshlab/alnParser.h>
#include <common/alnParser.h>
using namespace std;
using namespace vcg;

View File

@ -35,7 +35,7 @@
#include <vcg/complex/algorithms/clustering.h>
#include <vcg/complex/algorithms/hole.h>
#include <wrap/io_trimesh/export_ply.h>
#include <meshlab/alnParser.h>
#include <common/alnParser.h>
class EditArc3DPlugin : public QObject, public MeshEditInterface

View File

@ -40,7 +40,7 @@
#include <vcg/complex/algorithms/clustering.h>
#include <vcg/complex/algorithms/hole.h>
#include <wrap/io_trimesh/export_ply.h>
#include <meshlab/alnParser.h>
#include <common/alnParser.h>
FILE *logFP=0;
using namespace std;

View File

@ -1,6 +1,6 @@
#ifndef SIMPLEMESHPROVIDER_H
#define SIMPLEMESHPROVIDER_H
#include "../../meshlab/alnParser.h"
#include "../../common/alnParser.h"
#include <list>
#include <vector>
#include <vcg/space/box3.h>