Newer
Older
Import / research / 3d-z-maps / mview-0.3.3 / mview / mview.cpp
//
//    File: mview.cc
//
//    (C) 2000-2008 Helmut Cantzler
//
//    Licensed under the terms of the Lesser General Public License.
//

#include <QtGui>
#include <QString>

#include "mesh.h"

#include "mview.h"
#include "viewpointdialog.h"
#include "coordinates.h"

#include "p_mesh.h"
#include "gts_mesh.h"
#include "geomview_mesh.h"
#include "vrml1_mesh.h"
#include "vrml2_mesh.h"
#include "list_mesh.h"
#include "feature_mesh.h"
#include "ply_mesh.h"
#include "obj_mesh.h"
#include "vtk_mesh.h"
#include "x3d_mesh.h"
#include "shallo_mesh.h"

#include "icons/icon_fileopen.xpm"
#include "icons/icon_texture.xpm"
#include "icons/icon_solid.xpm"
#include "icons/icon_wire.xpm"
#include "icons/icon_point.xpm"
#include "icons/icon_front.xpm"
#include "icons/icon_feature.xpm"
#include "icons/icon_coordinates.xpm"

QProgressDialog *pd;

int updateProgress(int pos)
{
  static int q=0;

  if (q % 100 == 0)
    pd->setValue(pos);
  q++;

  return pd->wasCanceled();
}

void setTotal(int size)
{
  pd->setMaximum(size);
}

MView::MView(int argc, char **argv)
{
  //// Set OpenGL options ////

  QGLFormat f;
  f.setDoubleBuffer(TRUE);
  f.setDepth(TRUE);
  f.setStencil(TRUE);
  QGLFormat::setDefaultFormat(f);
  
  //// Init mesh display options ////

  settings = new GLMeshSettings();

  //// Open 3D model file, if specified in command line argument ////

  if (argc >= 2)
    {
      loadModelFile(argv[1], &settings->mesh);

      if (settings->mesh != NULL)
	{
	  // Map vertices and triangle centroids to mesh centroid
	  settings->mesh->moveToCentre();
	  settings->mesh->scaleIntoNormalSphere();
	}
    }      

  if (argc >= 3)
    {
      loadModelFile(argv[2], &settings->features);

      if (settings->features != NULL)
	{
	  settings->features->scaleAccordingToReferenceMesh(settings->mesh);
	}
    }

  //// Set-up main window

  setWindowTitle("Mesh Viewer");
  resize(580, 620);

  //// Set-up main widgets ////

  QWidget *box = new QWidget;
  
  QGridLayout *layout = new QGridLayout;
  layout->setMargin(10);
  layout->setSpacing(10);

  glmesh = new GLMesh(box, settings, true, -1);
  layout->addWidget(glmesh, 0, 0, 2, 4);

  clipping = new QSlider(box);
  clipping->setMinimum(-20);
  clipping->setMaximum(60);
  clipping->setValue(0);
  clipping->setToolTip("Clipping");
  connect(clipping, SIGNAL(valueChanged(int)), glmesh, SLOT(setClipping(int)));
  layout->addWidget(clipping, 0, 4, 2, 1);
  
  int xs[6] = { 0, 1, 1, 1, 2, 3 };
  int ys[6] = { 1, 0, 1, 2, 1, 1 };
  for (int i = 0; i < 6; i++)
  {
    glmeshCubeSides[i] = new GLMesh(box, settings, false, i);
    glmeshCubeSides[i]->setFixedSize(256, 256);
    layout->addWidget(glmeshCubeSides[i], ys[i] + 2, xs[i], 1, 1);
  }

  box->setLayout(layout);

  setCentralWidget(box);

  //// Set-up menus, toolbar and statusbar ////

  createActions();
  createMenus();
  createToolBars();
  createStatusBar();

  setStatus();

  // start timer for updating labelFPS every 3 seconds
  startTimer(3000);
  qWarning("here\n");

  // set default display options
  setDefaultConfig();

/*
  // Display OpenGL information
  printf("depth: %d\n", glmesh->format().depth() ? 1 : 0);
  printf("rgba: %d\n", glmesh->format().rgba() ? 1 : 0);
  printf("alpha: %d\n", glmesh->format().alpha() ? 1 : 0);
  printf("accum: %d\n", glmesh->format().accum() ? 1 : 0);
  printf("stencil: %d\n", glmesh->format().stencil() ? 1 : 0);
  printf("stereo: %d\n", glmesh->format().stereo() ? 1 : 0);
  printf("directRendering: %d\n", glmesh->format().directRendering() ? 1 : 0);
  printf("hasOverlay: %d\n", glmesh->format().hasOverlay() ? 1 : 0);
*/
  qWarning("here\n");
}

MView::~MView()
{
  settings->clear();
  delete settings;
}

void MView::createActions()
{
    openAct = new QAction(QIcon(icon_fileopen), tr("&Open model"), this);
    openAct->setShortcut(tr("O"));
    connect(openAct, SIGNAL(triggered()), this, SLOT(loadModel()) );

    openFeatAct = new QAction(tr("Open &features"), this);
    connect(openFeatAct, SIGNAL(triggered()), this, SLOT(loadFeatures()) );

    screenshotActs = new QActionGroup(this);
    QList<QByteArray> formats = QImageWriter::supportedImageFormats();
    for (int i = 0; i < formats.size(); ++i) {
	screenshotActs->addAction(formats.at(i).constData());
    }
    connect(screenshotActs, SIGNAL(triggered(QAction*)), 
	    this, SLOT(takeShot(QAction*)) );
    
    saveActs = new QActionGroup(this);
    saveActs->addAction("P Mesh");
    saveActs->addAction("GTS");
    saveActs->addAction("Geomview");
    saveActs->addAction("VRML 1");
    saveActs->addAction("VRML 2");
    saveActs->addAction("PLY");
    saveActs->addAction("OBJ");
    saveActs->addAction("VTK");
    saveActs->addAction("X3D");
    saveActs->addAction("Shallo");
    connect(saveActs, SIGNAL(triggered(QAction*)), 
	    this, SLOT(saveAs(QAction*)) );

    exitAct = new QAction(tr("&Quit"), this);
    exitAct->setShortcut(Qt::Key_Escape);
    connect(exitAct, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));

    dTextAct = new QAction(QIcon(icon_texture), tr("&Texture"), this);
    dTextAct->setCheckable(true);
    dTextAct->setShortcut(tr("1"));

    dSolidAct = new QAction(QIcon(icon_solid), tr("S&olid"), this);
    dSolidAct->setCheckable(true);
    dSolidAct->setShortcut(tr("2"));
    
    dFrontAct = new QAction(QIcon(icon_front), tr("F&rontlines"), this);
    dFrontAct->setCheckable(true);
    dFrontAct->setShortcut(tr("3"));
    
    dWireAct = new QAction(QIcon(icon_wire), tr("&Wireframe"), this);
    dWireAct->setCheckable(true);
    dWireAct->setShortcut(tr("4"));
    
    dPointAct = new QAction(QIcon(icon_point), tr("Po&ints"), this);
    dPointAct->setCheckable(true);
    dPointAct->setShortcut(tr("5"));
    
    dFeatAct = new QAction(QIcon(icon_feature), tr("F&eature"), this);
    dFeatAct->setCheckable(true);
    dFeatAct->setShortcut(tr("6"));
    
    displayActs = new QActionGroup(this);
    displayActs->addAction(dTextAct);
    displayActs->addAction(dSolidAct);
    displayActs->addAction(dFrontAct);
    displayActs->addAction(dWireAct);
    displayActs->addAction(dPointAct);
    displayActs->addAction(dFeatAct);
    connect(displayActs, SIGNAL(triggered(QAction*)), 
	    glmesh, SLOT(setDisplayMode(QAction*)) );

    pickAct = new QAction(QIcon(icon_coordinates), tr("&Pick objects"), this);
    pickAct->setCheckable(true);
    pickAct->setShortcut(tr("P"));
    connect(pickAct, SIGNAL(triggered(bool)), this, SLOT(togglePick(bool)) );

    lightAct = new QAction(tr("Lighting"), this);
    lightAct->setCheckable(true);
    lightAct->setShortcut(tr("L"));
    connect(lightAct, SIGNAL(triggered(bool)),
	    glmesh, SLOT(setLight(bool)) );

    polyAct = new QAction(tr("Show polygons"), this);
    polyAct->setCheckable(true);
    polyAct->setShortcut(tr("Y"));
    connect(polyAct, SIGNAL(triggered(bool)),
	    glmesh, SLOT(setPolygons(bool)) );

    shapeAct = new QAction(tr("Shape colours"), this);
    shapeAct->setCheckable(true);
    shapeAct->setShortcut(tr("S"));
    connect(shapeAct, SIGNAL(triggered(bool)),
	    glmesh, SLOT(setShapeColors(bool)) );

    normAct = new QAction(tr("Surface normals"), this);
    normAct->setCheckable(true);
    normAct->setShortcut(tr("N"));
    connect(normAct, SIGNAL(triggered(bool)), 
	    glmesh, SLOT(setNormals(bool)) );

    boundingAct = new QAction(tr("Bounding Box"), this);
    boundingAct->setCheckable(true);
    boundingAct->setShortcut(tr("B"));
    connect(boundingAct, SIGNAL(triggered(bool)), 
	    glmesh, SLOT(setBoundingBox(bool)) );

    cutAct = new QAction(tr("Cut back faces"), this);
    cutAct->setCheckable(true);
    cutAct->setShortcut(tr("C"));
    connect(cutAct, SIGNAL(triggered(bool)),
	    glmesh, SLOT(setBackFaces(bool)) );

    filtAct = new QAction(tr("Bilinear filtering"), this);
    filtAct->setCheckable(true);
    filtAct->setShortcut(tr("T"));
    connect(filtAct, SIGNAL(triggered(bool)),
	    glmesh, SLOT(setTextureFiltering(bool)) );

    featAct = new QAction(tr("Features"), this);
    featAct->setCheckable(true);
    featAct->setShortcut(tr("F"));
    connect(featAct, SIGNAL(triggered(bool)),
	    glmesh, SLOT(setFeatures(bool)) );

    keepAct = new QAction(tr("Keep aspect ratio"), this);
    keepAct->setCheckable(true);
    keepAct->setShortcut(tr("K"));
    connect(keepAct, SIGNAL(triggered(bool)),
	    glmesh, SLOT(setAspectRatio(bool)) );

    backAct = new QAction(tr("Background colour..."), this);
    backAct->setShortcut(tr("G"));
    connect(backAct, SIGNAL(triggered()), this, SLOT(setBackgroundColor()) );
    
    vSetAct = new QAction(tr("Set"), this);
    connect(vSetAct, SIGNAL(triggered()), this, SLOT(setView()) );

    vResAct = new QAction(tr("Reset"), this);
    connect(vResAct, SIGNAL(triggered()), this, SLOT(resetView()) );

    vSaveAct = new QAction(tr("Save"), this);
    connect(vSaveAct, SIGNAL(triggered()), this, SLOT(saveView()) );

    vCleaAct = new QAction(tr("Clear"), this);
    connect(vCleaAct, SIGNAL(triggered()), this, SLOT(clearViews()) );

    viewActs = new QActionGroup(this);
    connect(viewActs, SIGNAL(triggered(QAction*)), 
	    this, SLOT(loadView(QAction*)) );

    abouAct = new QAction(tr("&About"), this);
    connect(abouAct, SIGNAL(triggered()), this, SLOT(about()));
    
    abqtAct = new QAction(tr("About &Qt"), this);
    connect(abqtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
}

void MView::createMenus()
{
    QMenu *saveMenu = new QMenu(tr("&Save as"));
    saveMenu->addActions(saveActs->actions());

    QMenu *screenshotMenu = new QMenu(tr("&Take screenshot"));
    screenshotMenu->addActions(screenshotActs->actions());
    
    QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(openAct);
    fileMenu->addAction(openFeatAct);
    fileMenu->addSeparator();
    fileMenu->addMenu(saveMenu);
    fileMenu->addSeparator();
    fileMenu->addMenu(screenshotMenu);
    fileMenu->addSeparator();
    fileMenu->addAction(exitAct);
    
    QMenu *displayMenu = menuBar()->addMenu(tr("&Display"));
    displayMenu->addActions(displayActs->actions());
    displayMenu->addSeparator();
    displayMenu->addAction(pickAct);
    displayMenu->addSeparator();
    displayMenu->addAction(lightAct);
    displayMenu->addAction(polyAct);
    displayMenu->addAction(shapeAct);
    displayMenu->addAction(normAct);
    displayMenu->addAction(boundingAct);
    displayMenu->addAction(cutAct);
    displayMenu->addAction(filtAct);
    displayMenu->addAction(featAct);
    displayMenu->addAction(keepAct);
    displayMenu->addSeparator();
    displayMenu->addAction(backAct);

    viewpointMenu = menuBar()->addMenu(tr("&Viewpoint"));
    viewpointMenu->addAction(vSetAct);
    viewpointMenu->addAction(vResAct);
    viewpointMenu->addSeparator();
    viewpointMenu->addAction(vSaveAct);
    viewpointMenu->addAction(vCleaAct);
    viewpointMenu->addSeparator();

    QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
    helpMenu->addAction(abouAct);
    helpMenu->addAction(abqtAct);
}
 
void MView::createToolBars()
{
    QToolBar *tools = addToolBar(tr("Mesh Viewer Toolbar"));

    tools->addAction(openAct);
    tools->addSeparator();
    tools->addActions(displayActs->actions());
    tools->addSeparator();
    tools->addAction(pickAct);
    tools->addSeparator();

    QSpinBox *lighting = new QSpinBox(tools);
    lighting->setToolTip("Light intensity");
    lighting->setSingleStep(1);
    lighting->setMinimum(1);
    lighting->setMaximum(20);
    lighting->setValue(10);
    connect(lighting, SIGNAL(valueChanged(int)), 
	    glmesh, SLOT(setLightIntensity(int)));
    tools->addWidget(lighting);

    QSpinBox *lineWidth = new QSpinBox(tools);
    lineWidth->setToolTip("Line width");
    lineWidth->setSingleStep(1);
    lineWidth->setMinimum(1);
    lineWidth->setMaximum(20);
    lineWidth->setValue(1);
    connect(lineWidth, SIGNAL(valueChanged(int)), 
	    glmesh, SLOT(setLineSize(int)));
    tools->addWidget(lineWidth);

    QSpinBox *pointSize = new QSpinBox(tools);
    pointSize->setToolTip("Point size");
    pointSize->setSingleStep(1);
    pointSize->setMinimum(1);
    pointSize->setMaximum(20);
    pointSize->setValue(1);
    connect(pointSize, SIGNAL(valueChanged(int)),
	    glmesh, SLOT(setPointSize(int)));
    tools->addWidget(pointSize);
}

void MView::createStatusBar()
{
   labelMesh = new QLabel(statusBar());
   statusBar()->addWidget(labelMesh, 1);

   labelFeatures = new QLabel(statusBar());
   statusBar()->addWidget(labelFeatures, 1);

   labelFPS = new QLabel(" FPS: 0.0 ", statusBar());
   statusBar()->addPermanentWidget(labelFPS, 0);
}

void MView::loadModel()
{
  QString fn = QFileDialog::getOpenFileName(this, "Select a model file");

  if ( !fn.isEmpty() )
    {
      settings->clear();

      loadModelFile(fn.toAscii().constData(), &settings->mesh);

      if (settings->mesh != NULL)
	{
	  // Map vertices and triangle centroids to mesh centroid
	  settings->mesh->moveToCentre();
	  settings->mesh->scaleIntoNormalSphere();
	}

      glmesh->newMesh();
      for (int i = 0; i < 6; i++)
      {
          glmeshCubeSides[i]->newMesh();
      }
      setDefaultConfig();
      setStatus();
    }
}

void MView::loadFeatures()
{
  if (settings->mesh != NULL)
    {
      QString fn = QFileDialog::getOpenFileName(this, "Select a model file");

      if ( !fn.isEmpty() )
	{
	  settings->clearFeatures();

	  loadModelFile(fn.toAscii().constData(), &settings->features);

   	  if (settings->features != NULL)
	    {
	      settings->features->scaleAccordingToReferenceMesh(settings->mesh);
	    }

	  glmesh->newFeatures();
      for (int i = 0; i < 6; i++)
      {
          glmeshCubeSides[i]->newFeatures();
      }
	  setStatus();
	}
    }
}

int MView::loadModelFile(const char *fileName, Mesh **mesh)
{
  FILE *f;

  if ((f = fopen(fileName, "r")) == NULL)
    return 1;

  switch (Mesh::type(f))
    {
    case LIST_MESH:
      *mesh = new ListMesh();
      break;
    case P_MESH:
      *mesh = new PMesh();
      break;
    case OBJ_MESH:
      *mesh = new OBJMesh();
      break;
    case VTK_MESH:
      *mesh = new VTKMesh();
      break;
    case GTS_MESH:
      *mesh = new GTSMesh();
      break;
    case GEOMVIEW_MESH:
      *mesh = new GeomviewMesh();
      break;
    case PLY_MESH:
      *mesh = new PLYMesh();
      break;	
    case VRML1_MESH:
      *mesh = new Vrml1Mesh();
      break;
    case VRML2_MESH:
      *mesh = new Vrml2Mesh();
      break;
    case SHALLO_MESH:
      *mesh = new ShalloMesh();
      break;
    case FEATURES_MESH:
      *mesh = new FeatureMesh();
      break;
    default:
      fclose(f);
      return 2;
    }

  pd=new QProgressDialog("Loading...", "Cancel", 0, 0, this);
  pd->setWindowTitle("Please wait");

  if ((*mesh)->read(f, (int (*)(int)) updateProgress,
		    (void (*)(int)) setTotal) != 0)
    (*mesh)->clear();
  
  delete pd;
  fclose(f);

  setName(fileName, *mesh);

  return 0;
}

void MView::saveAs(QAction *a)
{
   QString format = a->text();
   QString filename = QFileDialog::getSaveFileName(
       this, "Choose a filename to save under");

  if (!filename.isEmpty())
    {
      Mesh *m = NULL;
      FILE *f;

      if ((f = fopen(filename.toAscii().data(), "w")) == NULL)
	return;

      if (format == "P Mesh")
	m = new PMesh();
      if (format == "GTS")
	m = new GTSMesh();
      if (format == "Geomview")
	m = new GeomviewMesh();
      if (format == "VRML 1")
	m = new Vrml1Mesh();
      if (format == "VRML 2")
	m = new Vrml2Mesh();
      if (format == "PLY")
	m = new PLYMesh();
      if (format == "OBJ")
	m = new OBJMesh();
      if (format == "VTK")
	m = new VTKMesh();
      if (format == "X3D")
	m = new X3DMesh();		
      if (format == "Shallo")
	m = new ShalloMesh();
      if (m != NULL)
	{
	  m->setMesh(settings->mesh);
	  m->write(f);
	  delete m;
	}

      fclose(f);
    }
}

void MView::takeShot(QAction *a)
{
   QString format = a->text();
   QString filename = QFileDialog::getSaveFileName(
       this, "Choose a filename to save under", "", "*." + format);

   if (!filename.isEmpty())
   {
      QImage image = glmesh->renderPixmap().toImage();

      if (image.save(filename, format.toAscii().data()) == FALSE)
	QMessageBox::warning(this, "Save screenshot", "Could not save image!");
    }


    for (int i = 0; i < 6; i++)
    {
      QImage image = glmeshCubeSides[i]->renderPixmap().toImage();
      QString file = filename + QString("side_%1_").arg(i);
      image.save(file, format.toAscii().data());
    }

}

void MView::closeText(void)
{
  textAct->trigger();
}

void MView::displayTexture(void)
{
  dTextAct->trigger();
}

void MView::closePick(void)
{
  pickAct->trigger();
}

void MView::togglePick(bool pickState)
{
  static CoordinatesWindow *coordinates;

  if (pickState)
    {
      QDesktopWidget desktop;

      coordinates = new CoordinatesWindow(this, settings->mesh);

      if ( frameGeometry().topRight().x() + coordinates->width() <= 
	   desktop.screen( desktop.primaryScreen() )->width() )

      	coordinates->move( frameGeometry().topRight().x() + 1,
			   frameGeometry().topRight().y() );

      else if ( frameGeometry().topLeft().x() - coordinates->width() >= 0 ) 

	coordinates->move( frameGeometry().topLeft().x() - 
			   coordinates->frameGeometry().width() - 8, 
			   frameGeometry().topLeft().y() );

      coordinates->show();
    }
  else
    delete coordinates;

  glmesh->setPick(pickState, pickState ? coordinates : NULL);
}

void MView::setBackgroundColor()
{
  QColor c = QColorDialog::getColor();

  glmesh->setBackgroundColor(c);
}

void MView::resetView()
{
  glmesh->resetViewpoint();
  for (int i = 0; i < 6; i++)
  {
      glmeshCubeSides[i]->resetViewpoint();
  }
  clipping->setValue(0);
}

void MView::setView()
{
  GLMeshSettings s = *settings;
  ViewpointDialog vpd(this, &s);

  if (vpd.exec() == QDialog::Accepted)
  {
    glmesh->setViewpoint(s);
    for (int i = 0; i < 6; i++)
    {
        glmeshCubeSides[i]->setViewpoint(s);
    }
    clipping->setValue( (int) (-s.clipping*10) );
  }
}

void MView::clearViews()
{
  QMap<QAction*, GLMeshSettings>::Iterator it;

  for(it = viewpoints.begin(); it != viewpoints.end(); ++it )
  {
    viewActs->removeAction(it.key());
    viewpointMenu->removeAction(it.key());

    delete it.key();
  }

  viewpoints.clear();
}

void MView::saveView()
{
  QString name( tr("View %1").arg(viewpoints.count()+1) );

  QAction *a = new QAction(name, this);

  viewActs->addAction(a);
  viewpointMenu->addAction(a);

  viewpoints.insert(a, *settings);
}

void MView::loadView(QAction *a)
{
  glmesh->setViewpoint( viewpoints[a] );
  for (int i = 0; i < 6; i++)
  {
      glmeshCubeSides[i]->setViewpoint(viewpoints[a]);
  }
  clipping->setValue( (int) (-viewpoints[a].clipping*25) );
}

void MView::about()
{
   QMessageBox::about(this, "Mesh Viewer 0.3.3",
   "\nCopyright (c) 2001-2010 Helmut Cantzler < cantzler at gmx dot net >\n\n"
   "This program can be freely used and distributed according\n"
   "to the terms of the GNU Lesser General Public License.\n\n"
   "For more information visit the Mesh Viewer web site at:\n"
   "http://mview.sourceforge.net/\n");
}

void MView::setDefaultConfig()
{
  setOption(lightAct, true);
  setOption(polyAct, true);
  setOption(shapeAct, false);
  setOption(normAct, false);
  setOption(boundingAct, false);
  setOption(cutAct, false);
  setOption(filtAct, false);
  setOption(featAct, false);
  setOption(keepAct, true);
  setOption(dSolidAct, true);
}

void MView::setOption(QAction *a, bool b)
{
  if ( a )
  {
    a->setChecked(!b);
    a->trigger();
  }
}

void MView::setStatus()
{ 
  QString s;

  if (!name.isEmpty())
    {
      s = "";

      if (settings->mesh != NULL)
	{
	  int ver = settings->mesh->numberOfVertices();
	  int tri = settings->mesh->numberOfTriangles();

	  s = name + QString(": %1 vertices & %2 triangles ").arg(ver).arg(tri);
	}

      labelMesh->setText(s);
  
      s = "";

      if (settings->features != NULL)
	{
	  int ver = settings->features->numberOfVertices();
	  int edg = settings->features->numberOfEdges();

	  if (edg > 0)
	    s = QString(" Features: %1 edges ").arg(edg);
	  else
	    if (ver > 0)
	      s = QString(" Features: %1 points ").arg(ver);
	}

      labelFeatures->setText(s);
    }
}

void MView::setName(QString fileName, Mesh *mesh)
{
  QFileInfo fi(fileName);
  name = fi.fileName();
  fileName.chop(name.length());

  mesh->setName(name.toAscii().constData());
  mesh->setPath(fileName.toAscii().constData());
}

void MView::timerEvent(QTimerEvent *e)
{
  QString s;
  
  s.sprintf(" FPS: %1.1f ", glmesh->getFps());
  labelFPS->setText(s);
}