First checkin for OpenMesh 2.0
git-svn-id: http://www.openmesh.org/svnrepo/OpenMesh/trunk@2 fdac6126-5c0c-442c-9429-916003d36597
This commit is contained in:
17
Tools/Utils/ACGMakefile
Normal file
17
Tools/Utils/ACGMakefile
Normal file
@@ -0,0 +1,17 @@
|
||||
#== SYSTEM PART -- DON'T TOUCH ==============================================
|
||||
include $(ACGMAKE)/Config
|
||||
#==============================================================================
|
||||
|
||||
|
||||
SUBDIRS = $(call find-subdirs)
|
||||
|
||||
PACKAGES :=
|
||||
|
||||
PROJ_LIBS :=
|
||||
|
||||
MODULES := cxxlib
|
||||
|
||||
|
||||
#== SYSTEM PART -- DON'T TOUCH ==============================================
|
||||
include $(ACGMAKE)/Rules
|
||||
#==============================================================================
|
||||
57
Tools/Utils/Config.hh
Normal file
57
Tools/Utils/Config.hh
Normal file
@@ -0,0 +1,57 @@
|
||||
//=============================================================================
|
||||
//
|
||||
// OpenMesh
|
||||
// Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen
|
||||
// www.openmesh.org
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// License
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, version 2.1.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// $Revision: 1802 $
|
||||
// $Date: 2008-05-19 11:55:07 +0200 (Mo, 19. Mai 2008) $
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
/** \file Tools/Utils/Config.hh
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Defines
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef OPENMESH_UTILS_CONFIG_HH
|
||||
#define OPENMESH_UTILS_CONFIG_HH
|
||||
|
||||
|
||||
//== INCLUDES =================================================================
|
||||
|
||||
#include <OpenMesh/Core/System/config.h>
|
||||
|
||||
|
||||
//== NAMESPACES ===============================================================
|
||||
|
||||
#define BEGIN_NS_UTILS namespace Utils {
|
||||
#define END_NS_UTILS }
|
||||
|
||||
|
||||
//=============================================================================
|
||||
#endif // OPENMESH_UTILS_CONFIG_HH defined
|
||||
//=============================================================================
|
||||
80
Tools/Utils/GLConstAsString.hh
Normal file
80
Tools/Utils/GLConstAsString.hh
Normal file
@@ -0,0 +1,80 @@
|
||||
/*===========================================================================*\
|
||||
* *
|
||||
* OpenMesh *
|
||||
* Copyright (C) 2001-2003 by Computer Graphics Group, RWTH Aachen *
|
||||
* www.openmesh.org *
|
||||
* *
|
||||
*---------------------------------------------------------------------------*
|
||||
* *
|
||||
* License *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or modify it *
|
||||
* under the terms of the GNU Lesser General Public License as published *
|
||||
* by the Free Software Foundation, version 2.1. *
|
||||
* *
|
||||
* This library 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 *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
|
||||
* *
|
||||
\*===========================================================================*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// CLASS newClass
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
|
||||
#ifndef OPENMESH_UTILS_GLCONSTASSTRING_HH
|
||||
#define OPENMESH_UTILS_GLCONSTASSTRING_HH
|
||||
|
||||
|
||||
//== INCLUDES =================================================================
|
||||
|
||||
#include <OpenMesh/Core/System/config.h>
|
||||
#include <GL/glut.h>
|
||||
|
||||
|
||||
//== FORWARDDECLARATIONS ======================================================
|
||||
|
||||
|
||||
//== NAMESPACES ===============================================================
|
||||
|
||||
namespace OpenMesh {
|
||||
namespace Utils {
|
||||
|
||||
//== CLASS DEFINITION =========================================================
|
||||
|
||||
inline
|
||||
const char *GLenum_as_string( GLenum _m )
|
||||
{
|
||||
#define MODE(M) case M:return #M
|
||||
switch( _m )
|
||||
{
|
||||
MODE(GL_POINTS);
|
||||
MODE(GL_LINES);
|
||||
MODE(GL_LINE_STRIP);
|
||||
MODE(GL_LINE_LOOP);
|
||||
MODE(GL_TRIANGLES);
|
||||
MODE(GL_TRIANGLE_STRIP);
|
||||
MODE(GL_TRIANGLE_FAN);
|
||||
MODE(GL_QUADS);
|
||||
MODE(GL_QUAD_STRIP);
|
||||
MODE(GL_POLYGON);
|
||||
default: return "<unknown>";
|
||||
}
|
||||
#undef MODE
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
} // namespace Utils
|
||||
} // namespace OpenMesh
|
||||
//=============================================================================
|
||||
#endif // OPENMESH_UTILS_GLCONSTASSTRING_HH defined
|
||||
//=============================================================================
|
||||
|
||||
498
Tools/Utils/Gnuplot.cc
Normal file
498
Tools/Utils/Gnuplot.cc
Normal file
@@ -0,0 +1,498 @@
|
||||
////////////////////////////////////////////
|
||||
//
|
||||
// A C++ interface to gnuplot.
|
||||
//
|
||||
// This is a direct translation from the C interface
|
||||
// written by N. Devillard (which is available from
|
||||
// http://ndevilla.free.fr/gnuplot/).
|
||||
//
|
||||
// As in the C interface this uses pipes and so wont
|
||||
// run on a system that does'nt have POSIX pipe
|
||||
// support
|
||||
//
|
||||
// Rajarshi Guha
|
||||
// <rajarshi@presidency.com>
|
||||
//
|
||||
// 07/03/03
|
||||
//
|
||||
////////////////////////////////////////////
|
||||
|
||||
#include "Gnuplot.hh"
|
||||
#include <stdarg.h>
|
||||
#ifdef WIN32
|
||||
# include <io.h>
|
||||
#else
|
||||
# include <fcntl.h> // X_OK
|
||||
# include <unistd.h> // access
|
||||
# define PATH_MAXNAMESZ 4096
|
||||
#endif
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <list>
|
||||
|
||||
#if defined(WIN32)
|
||||
# define pclose _pclose
|
||||
# define popen _popen
|
||||
# define access _access
|
||||
# define ACCESS_OK 0
|
||||
# define PATH_SEP ";"
|
||||
# define MKTEMP_AND_CHECK_FAILED(name) (_mktemp(name) == NULL)
|
||||
#else
|
||||
# define ACCESS_OK X_OK
|
||||
# define PATH_SEP ":"
|
||||
# define MKTEMP_AND_CHECK_FAILED(name) (mkstemp(name) == -1)
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
/////////////////////////////
|
||||
//
|
||||
// A string tokenizer taken from
|
||||
// http://www.sunsite.ualberta.ca/
|
||||
// Documentation/Gnu/libstdc++-2.90.8/html/21_strings/stringtok_std_h.txt
|
||||
//
|
||||
/////////////////////////////
|
||||
|
||||
template <typename Container>
|
||||
void
|
||||
stringtok (Container &container, string const &in,
|
||||
const char * const delimiters = " \t\n")
|
||||
{
|
||||
const string::size_type len = in.length();
|
||||
|
||||
string::size_type i = 0;
|
||||
|
||||
while ( i < len )
|
||||
{
|
||||
// eat leading whitespace
|
||||
i = in.find_first_not_of (delimiters, i);
|
||||
if (i == string::npos)
|
||||
return; // nothing left but white space
|
||||
|
||||
// find the end of the token
|
||||
string::size_type j = in.find_first_of (delimiters, i);
|
||||
|
||||
// push token
|
||||
if (j == string::npos)
|
||||
{
|
||||
container.push_back (in.substr(i));
|
||||
return;
|
||||
} else
|
||||
container.push_back (in.substr(i, j-i));
|
||||
|
||||
// set up for next loop
|
||||
i = j + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifdef WIN32
|
||||
std::string Gnuplot::gnuplot_executable_ = "pgnuplot.exe";
|
||||
#else
|
||||
std::string Gnuplot::gnuplot_executable_ = "gnuplot";
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
Gnuplot::Gnuplot(void)
|
||||
{
|
||||
init();
|
||||
set_style("points");
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
Gnuplot::Gnuplot(const string &style)
|
||||
{
|
||||
init();
|
||||
set_style(style);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
Gnuplot::Gnuplot(const string &title,
|
||||
const string &style,
|
||||
const string &labelx, const string &labely,
|
||||
vector<double> x, vector<double> y)
|
||||
{
|
||||
init();
|
||||
|
||||
if (x.size() == 0 || y.size() == 0)
|
||||
throw GnuplotException("vectors too small");
|
||||
|
||||
if (style == "")
|
||||
this->set_style("lines");
|
||||
else
|
||||
this->set_style(style);
|
||||
|
||||
if (labelx == "")
|
||||
this->set_xlabel("X");
|
||||
else
|
||||
this->set_xlabel(labelx);
|
||||
if (labely == "")
|
||||
this->set_ylabel("Y");
|
||||
else
|
||||
this->set_ylabel(labely);
|
||||
|
||||
this->plot_xy(x,y,title);
|
||||
|
||||
cout << "Press enter to continue" << endl;
|
||||
while (getchar() != '\n'){}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
Gnuplot::Gnuplot(const string &title, const string &style,
|
||||
const string &labelx, const string &labely,
|
||||
vector<double> x)
|
||||
{
|
||||
init();
|
||||
|
||||
if (x.size() == 0)
|
||||
throw GnuplotException("vector too small");
|
||||
if (!this->gnucmd)
|
||||
throw GnuplotException("Could'nt open connection to gnuplot");
|
||||
|
||||
if (style == "")
|
||||
this->set_style("lines");
|
||||
else
|
||||
this->set_style(style);
|
||||
|
||||
if (labelx == "")
|
||||
this->set_xlabel("X");
|
||||
else
|
||||
this->set_xlabel(labelx);
|
||||
if (labely == "")
|
||||
this->set_ylabel("Y");
|
||||
else
|
||||
this->set_ylabel(labely);
|
||||
|
||||
this->plot_x(x,title);
|
||||
|
||||
cout << "Press enter to continue" << endl;
|
||||
while (getchar() != '\n'){}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
Gnuplot::~Gnuplot()
|
||||
{
|
||||
if ((this->to_delete).size() > 0)
|
||||
{
|
||||
for (size_t i = 0; i < this->to_delete.size(); i++)
|
||||
remove(this->to_delete[i].c_str());
|
||||
}
|
||||
|
||||
if (pclose(this->gnucmd) == -1)
|
||||
cerr << "Problem closing communication to gnuplot" << endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
bool Gnuplot::get_program_path(const string pname)
|
||||
{
|
||||
list<string> ls;
|
||||
char *path;
|
||||
|
||||
path = getenv("PATH");
|
||||
if (!path)
|
||||
return false;
|
||||
|
||||
stringtok(ls, path, PATH_SEP);
|
||||
|
||||
for (list<string>::const_iterator i = ls.begin(); i != ls.end(); ++i)
|
||||
{
|
||||
string tmp = (*i) + "/" + pname;
|
||||
if ( access(tmp.c_str(), ACCESS_OK) == 0 )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void Gnuplot::reset_plot(void)
|
||||
{
|
||||
if (this->to_delete.size() > 0)
|
||||
{
|
||||
for (size_t i = 0; i < this->to_delete.size(); i++)
|
||||
remove(this->to_delete[i].c_str());
|
||||
}
|
||||
this->nplots = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void Gnuplot::set_style(const string &stylestr)
|
||||
{
|
||||
if (stylestr != "lines" &&
|
||||
stylestr != "points" &&
|
||||
stylestr != "linespoints" &&
|
||||
stylestr != "impulses" &&
|
||||
stylestr != "dots" &&
|
||||
stylestr != "steps" &&
|
||||
stylestr != "errorbars" &&
|
||||
stylestr != "boxes" &&
|
||||
stylestr != "boxerrorbars")
|
||||
this->pstyle = string("points");
|
||||
else
|
||||
this->pstyle = stylestr;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void Gnuplot::cmd(const char *_cmd, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char local_cmd[GP_CMD_SIZE];
|
||||
|
||||
va_start(ap, _cmd);
|
||||
vsprintf(local_cmd, _cmd, ap);
|
||||
va_end(ap);
|
||||
|
||||
strcat(local_cmd,"\n");
|
||||
fputs(local_cmd,this->gnucmd);
|
||||
fflush(this->gnucmd);
|
||||
return;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void Gnuplot::set_ylabel(const string &label)
|
||||
{
|
||||
ostringstream cmdstr;
|
||||
|
||||
cmdstr << "set xlabel \"" << label << "\"";
|
||||
this->cmd(cmdstr.str().c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void Gnuplot::set_xlabel(const string &label)
|
||||
{
|
||||
ostringstream cmdstr;
|
||||
|
||||
cmdstr << "set xlabel \"" << label << "\"";
|
||||
this->cmd(cmdstr.str().c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Plots a linear equation (where you supply the
|
||||
// slope and intercept)
|
||||
//
|
||||
void Gnuplot::plot_slope(double a, double b, const string &title)
|
||||
{
|
||||
ostringstream stitle;
|
||||
ostringstream cmdstr;
|
||||
|
||||
if (title == "")
|
||||
stitle << "no title";
|
||||
else
|
||||
stitle << title;
|
||||
|
||||
if (this->nplots > 0)
|
||||
cmdstr << "replot " << a << " * x + " << b << " title \"" << stitle.str() << "\" with " << pstyle;
|
||||
else
|
||||
cmdstr << "plot " << a << " * x + " << b << " title \"" << stitle.str() << "\" with " << pstyle;
|
||||
this->cmd(cmdstr.str().c_str());
|
||||
this->nplots++;
|
||||
return;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Plot an equation which is supplied as a string
|
||||
//
|
||||
void Gnuplot::plot_equation(const string &equation, const string &title)
|
||||
{
|
||||
string titlestr, plotstr;
|
||||
ostringstream cmdstr;
|
||||
|
||||
if (title == "")
|
||||
titlestr = "no title";
|
||||
else
|
||||
titlestr = title;
|
||||
|
||||
if (this->nplots > 0)
|
||||
plotstr = "replot";
|
||||
else
|
||||
plotstr = "plot";
|
||||
|
||||
cmdstr << plotstr << " " << equation << " " << "title \"" << titlestr << "\" with " << this->pstyle;
|
||||
this->cmd(cmdstr.str().c_str());
|
||||
this->nplots++;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void Gnuplot::plot_x(vector<double> d, const string &title)
|
||||
{
|
||||
ofstream tmp;
|
||||
ostringstream cmdstr;
|
||||
#ifdef WIN32
|
||||
char name[] = "gnuplotiXXXXXX";
|
||||
#else
|
||||
char name[] = "/tmp/gnuplotiXXXXXX";
|
||||
#endif
|
||||
|
||||
if (this->to_delete.size() == GP_MAX_TMP_FILES - 1)
|
||||
{
|
||||
cerr << "Maximum number of temporary files reached (" << GP_MAX_TMP_FILES << "): cannot open more files" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
//open temporary files for output
|
||||
#ifdef WIN32
|
||||
if ( _mktemp(name) == NULL)
|
||||
#else
|
||||
if ( mkstemp(name) == -1 )
|
||||
#endif
|
||||
{
|
||||
cerr << "Cannot create temporary file: exiting plot" << endl;
|
||||
return;
|
||||
}
|
||||
tmp.open(name);
|
||||
if (tmp.bad())
|
||||
{
|
||||
cerr << "Cannot create temorary file: exiting plot" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Save the temporary filename
|
||||
//
|
||||
this->to_delete.push_back(name);
|
||||
|
||||
//
|
||||
// write the data to file
|
||||
//
|
||||
for (size_t i = 0; i < d.size(); i++)
|
||||
tmp << d[i] << endl;
|
||||
tmp.flush();
|
||||
tmp.close();
|
||||
|
||||
//
|
||||
// command to be sent to gnuplot
|
||||
//
|
||||
cmdstr << ( (this->nplots > 0) ? "replot " : "plot ");
|
||||
|
||||
if (title.empty())
|
||||
cmdstr << "\"" << name << "\" with " << this->pstyle;
|
||||
else
|
||||
cmdstr << "\"" << name << "\" title \"" << title << "\" with "
|
||||
<< this->pstyle;
|
||||
|
||||
//
|
||||
// Do the actual plot
|
||||
//
|
||||
this->cmd(cmdstr.str().c_str());
|
||||
this->nplots++;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void Gnuplot::plot_xy(vector<double> x, vector<double> y, const string &title)
|
||||
{
|
||||
ofstream tmp;
|
||||
ostringstream cmdstr;
|
||||
#ifdef WIN32
|
||||
char name[] = "gnuplotiXXXXXX";
|
||||
#else
|
||||
char name[] = "/tmp/gnuplotiXXXXXX";
|
||||
#endif
|
||||
|
||||
// should raise an exception
|
||||
if (x.size() != y.size())
|
||||
return;
|
||||
|
||||
if ((this->to_delete).size() == GP_MAX_TMP_FILES - 1)
|
||||
{
|
||||
std::stringstream s;
|
||||
s << "Maximum number of temporary files reached ("
|
||||
<< GP_MAX_TMP_FILES << "): cannot open more files" << endl;
|
||||
throw GnuplotException( s.str() );
|
||||
}
|
||||
|
||||
//open temporary files for output
|
||||
//
|
||||
if (MKTEMP_AND_CHECK_FAILED(name))
|
||||
throw GnuplotException("Cannot create temporary file: exiting plot");
|
||||
|
||||
tmp.open(name);
|
||||
if (tmp.bad())
|
||||
throw GnuplotException("Cannot create temorary file: exiting plot");
|
||||
|
||||
// Save the temporary filename
|
||||
//
|
||||
this->to_delete.push_back(name);
|
||||
|
||||
// Write the data to file
|
||||
//
|
||||
size_t N = std::min(x.size(), y.size());
|
||||
for (size_t i = 0; i < N; i++)
|
||||
tmp << x[i] << " " << y[i] << endl;
|
||||
tmp.flush();
|
||||
tmp.close();
|
||||
|
||||
//
|
||||
// command to be sent to gnuplot
|
||||
//
|
||||
if (this->nplots > 0)
|
||||
cmdstr << "replot ";
|
||||
else cmdstr << "plot ";
|
||||
if (title == "")
|
||||
cmdstr << "\"" << name << "\" with " << this->pstyle;
|
||||
else
|
||||
cmdstr << "\"" << name << "\" title \"" << title << "\" with " << this->pstyle;
|
||||
|
||||
//
|
||||
// Do the actual plot
|
||||
//
|
||||
this->cmd(cmdstr.str().c_str());
|
||||
this->nplots++;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void Gnuplot::init()
|
||||
{
|
||||
if (!this->get_program_path(gnuplot_executable_))
|
||||
{
|
||||
this->valid = false;
|
||||
throw GnuplotException("Can't find gnuplot in your PATH");
|
||||
}
|
||||
|
||||
this->gnucmd = popen(gnuplot_executable_.c_str(),"w");
|
||||
if (!this->gnucmd)
|
||||
{
|
||||
this->valid = false;
|
||||
throw GnuplotException("Couldn't open connection to gnuplot");
|
||||
}
|
||||
this->nplots = 0;
|
||||
this->valid = true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
184
Tools/Utils/Gnuplot.hh
Normal file
184
Tools/Utils/Gnuplot.hh
Normal file
@@ -0,0 +1,184 @@
|
||||
////////////////////////////////////////////
|
||||
//
|
||||
// A C++ interface to gnuplot.
|
||||
//
|
||||
// This is a direct translation from the C interface
|
||||
// written by N. Devillard (which is available from
|
||||
// http://ndevilla.free.fr/gnuplot/).
|
||||
//
|
||||
// As in the C interface this uses pipes and so wont
|
||||
// run on a system that doesn't have POSIX pipe
|
||||
// support
|
||||
//
|
||||
// Rajarshi Guha
|
||||
// <rajarshi@presidency.com>
|
||||
//
|
||||
// 07/03/03
|
||||
//
|
||||
////////////////////////////////////////////
|
||||
//
|
||||
// A little correction for Win32 compatibility
|
||||
// and MS VC 6.0 done by V.Chyzhdzenka
|
||||
//
|
||||
// Notes:
|
||||
// 1. Added private method Gnuplot::init().
|
||||
// 2. Temporary file is created in th current
|
||||
// folder but not in /tmp.
|
||||
// 3. Added #indef WIN32 e.t.c. where is needed.
|
||||
// 4. Added private member m_sGNUPlotFileName is
|
||||
// a name of executed GNUPlot file.
|
||||
//
|
||||
// Viktor Chyzhdzenka
|
||||
// e-mail: chyzhdzenka@mail.ru
|
||||
//
|
||||
// 20/05/03
|
||||
//
|
||||
////////////////////////////////////////////
|
||||
|
||||
#ifndef _GNUPLOT_HH
|
||||
#define _GNUPLOT_HH
|
||||
|
||||
#include <OpenMesh/Core/System/config.hh>
|
||||
// #ifndef WIN32
|
||||
// # include <unistd.h>
|
||||
// #else
|
||||
// # pragma warning (disable : 4786) // Disable 4786 warning for MS VC 6.0
|
||||
// #endif
|
||||
#if defined(OM_CC_MIPS)
|
||||
# include <stdio.h>
|
||||
#else
|
||||
# include <cstdio>
|
||||
#endif
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifdef WIN32
|
||||
# define GP_MAX_TMP_FILES 27 //27 temporary files it's Microsoft restriction
|
||||
#else
|
||||
# define GP_MAX_TMP_FILES 64
|
||||
# define GP_TMP_NAME_SIZE 512
|
||||
# define GP_TITLE_SIZE 80
|
||||
#endif
|
||||
#define GP_CMD_SIZE 1024
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
using namespace std;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// Exception thrown by class Gnuplot
|
||||
class GnuplotException : public runtime_error
|
||||
{
|
||||
public:
|
||||
GnuplotException(const string &msg) : runtime_error(msg){}
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/** Utility class interfacing with Gnuplot.
|
||||
*
|
||||
* \note The plot will be visible as long as the object is not destructed.
|
||||
*
|
||||
* \author Rajarshi Guha (C++ API based on the C API by Nicolas Devillard)
|
||||
*
|
||||
* \see <a
|
||||
* href="http://ndevilla.free.fr/gnuplot/">http://ndevilla.free.fr/gnuplot/</a>
|
||||
* more information.
|
||||
*/
|
||||
class Gnuplot
|
||||
{
|
||||
private:
|
||||
|
||||
FILE *gnucmd;
|
||||
string pstyle;
|
||||
vector<string> to_delete;
|
||||
int nplots;
|
||||
bool get_program_path(const string);
|
||||
bool valid;
|
||||
|
||||
// Name of executed GNUPlot file
|
||||
static string gnuplot_executable_;
|
||||
|
||||
void init();
|
||||
|
||||
public:
|
||||
|
||||
/// \name Constructors
|
||||
//@{
|
||||
/// Default constructor.
|
||||
Gnuplot();
|
||||
|
||||
/// Set a style during construction.
|
||||
Gnuplot(const string & _style);
|
||||
|
||||
/// Constructor calling plot_xy().
|
||||
Gnuplot(const string & _title,
|
||||
const string & _style,
|
||||
const string & _xlabel,
|
||||
const string & _ylabel,
|
||||
vector<double> _x, vector<double> _y);
|
||||
|
||||
/// Constructor calling plot_x().
|
||||
Gnuplot(const string &_title,
|
||||
const string &_style,
|
||||
const string &_xlabel,
|
||||
const string &_ylabel,
|
||||
vector<double> _x);
|
||||
//@}
|
||||
|
||||
~Gnuplot();
|
||||
|
||||
/// Send a command to gnuplot (low-level function use by all plot functions.)
|
||||
void cmd(const char *_cmd, ...);
|
||||
|
||||
/// \name Gnuplot settings
|
||||
//@{
|
||||
void set_style(const string & _style); ///< set line style
|
||||
void set_ylabel(const string & _ylabel); ///< set x axis label
|
||||
void set_xlabel(const string & _xlabel); ///< set x axis label
|
||||
//@}
|
||||
|
||||
/// \name plot functions
|
||||
//@{
|
||||
|
||||
/// Plot a single vector
|
||||
void plot_x(vector<double> _x, const string &_title);
|
||||
|
||||
/// Plot x,y pairs
|
||||
void plot_xy(vector<double> _x, vector<double> _y, const string &_title);
|
||||
|
||||
/// Plot an equation of the form: y = ax + b
|
||||
/// You supply a and b
|
||||
void plot_slope(
|
||||
double _a,
|
||||
double _b,
|
||||
const string & _title
|
||||
);
|
||||
|
||||
/// Plot an equation supplied as a string
|
||||
void plot_equation(
|
||||
const string & _equation,
|
||||
const string & _title
|
||||
);
|
||||
|
||||
/// If multiple plots are present it will clear the plot area
|
||||
void reset_plot(void);
|
||||
|
||||
//@}
|
||||
|
||||
/// Is \c Self valid?
|
||||
bool is_valid(void) const { return valid; }
|
||||
|
||||
/// Is \c Self active, i.e. does it have an active plot?
|
||||
bool is_active(void) const { return this->nplots > 0; }
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
#endif // _GNUPLOT_HH
|
||||
// ============================================================================
|
||||
|
||||
353
Tools/Utils/HeapT.hh
Normal file
353
Tools/Utils/HeapT.hh
Normal file
@@ -0,0 +1,353 @@
|
||||
//=============================================================================
|
||||
//
|
||||
// OpenMesh
|
||||
// Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen
|
||||
// www.openmesh.org
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// License
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, version 2.1.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// $Revision: 1802 $
|
||||
// $Date: 2008-05-19 11:55:07 +0200 (Mo, 19. Mai 2008) $
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
/** \file HeapT.hh
|
||||
A generic heap class
|
||||
**/
|
||||
/** Martin, 26.12.2004:
|
||||
1) replaced resize(size()-1) with pop_back(), since the later is more efficient
|
||||
2) replaced interface_.set_heap_position(entry(0), -1); with reset_heap_position()
|
||||
3) added const modifier to various functions
|
||||
TODO: in the moment the heap does not conform to the HeapInterface specification,
|
||||
i.e., copies are passed instead of references. This is especially important
|
||||
for set_heap_position(), where the reference argument is non-const. The
|
||||
specification should be changed to reflect that the heap actually (only?)
|
||||
works when the heap entry is nothing more but a handle.
|
||||
TODO: change the specification of HeapInterface to make less(), greater() and
|
||||
get_heap_position() const. Needs changing DecimaterT. Might break
|
||||
someone's code.
|
||||
*/
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// CLASS HeapT
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef OPENMESH_UTILS_HEAPT_HH
|
||||
#define OPENMESH_UTILS_HEAPT_HH
|
||||
|
||||
|
||||
//== INCLUDES =================================================================
|
||||
|
||||
#include "Config.hh"
|
||||
#include <vector>
|
||||
#include <OpenMesh/Core/System/omstream.hh>
|
||||
|
||||
//== NAMESPACE ================================================================
|
||||
|
||||
namespace OpenMesh { // BEGIN_NS_OPENMESH
|
||||
namespace Utils { // BEGIN_NS_UTILS
|
||||
|
||||
//== CLASS DEFINITION =========================================================
|
||||
|
||||
|
||||
/** This class demonstrates the HeapInterface's interface. If you
|
||||
* want to build your customized heap you will have to specity a heap
|
||||
* interface class and use this class as a template parameter for the
|
||||
* class HeapT. This class defines the interface that this heap
|
||||
* interface has to implement.
|
||||
*
|
||||
* \see HeapT
|
||||
*/
|
||||
template <class HeapEntry>
|
||||
struct HeapInterfaceT
|
||||
{
|
||||
/// Comparison of two HeapEntry's: strict less
|
||||
bool less(const HeapEntry& _e1, const HeapEntry& _e2);
|
||||
|
||||
/// Comparison of two HeapEntry's: strict greater
|
||||
bool greater(const HeapEntry& _e1, const HeapEntry& _e2);
|
||||
|
||||
/// Get the heap position of HeapEntry _e
|
||||
int get_heap_position(const HeapEntry& _e);
|
||||
|
||||
/// Set the heap position of HeapEntry _e
|
||||
void set_heap_position(HeapEntry& _e, int _i);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** \class HeapT HeapT.hh <OSG/Utils/HeapT.hh>
|
||||
*
|
||||
* An efficient, highly customizable heap.
|
||||
*
|
||||
* The main difference (and performace boost) of this heap compared
|
||||
* to e.g. the heap of the STL is that here to positions of the
|
||||
* heap's elements are accessible from the elements themself.
|
||||
* Therefore if one changes the priority of an element one does not
|
||||
* have to remove and re-insert this element, but can just call the
|
||||
* update(HeapEntry) method.
|
||||
*
|
||||
* This heap class is parameterized by two template arguments:
|
||||
* \li the class \c HeapEntry, that will be stored in the heap
|
||||
* \li the HeapInterface telling the heap how to compare heap entries and
|
||||
* how to store the heap positions in the heap entries.
|
||||
*
|
||||
* As an example how to use the class see declaration of class
|
||||
* Decimater::DecimaterT.
|
||||
*
|
||||
* \see HeapInterfaceT
|
||||
*/
|
||||
|
||||
template <class HeapEntry, class HeapInterface=HeapEntry>
|
||||
class HeapT : private std::vector<HeapEntry>
|
||||
{
|
||||
private:
|
||||
typedef std::vector<HeapEntry> Base;
|
||||
|
||||
public:
|
||||
|
||||
/// Constructor
|
||||
HeapT() : HeapVector() {}
|
||||
|
||||
/// Construct with a given \c HeapIterface.
|
||||
HeapT(const HeapInterface& _interface)
|
||||
: HeapVector(), interface_(_interface)
|
||||
{}
|
||||
|
||||
/// Destructor.
|
||||
~HeapT(){};
|
||||
|
||||
|
||||
/// clear the heap
|
||||
void clear() { HeapVector::clear(); }
|
||||
|
||||
/// is heap empty?
|
||||
bool empty() const { return HeapVector::empty(); }
|
||||
|
||||
/// returns the size of heap
|
||||
unsigned int size() const { return HeapVector::size(); }
|
||||
|
||||
/// reserve space for _n entries
|
||||
void reserve(unsigned int _n) { HeapVector::reserve(_n); }
|
||||
|
||||
/// reset heap position to -1 (not in heap)
|
||||
void reset_heap_position(HeapEntry _h)
|
||||
{ interface_.set_heap_position(_h, -1); }
|
||||
|
||||
/// is an entry in the heap?
|
||||
bool is_stored(HeapEntry _h)
|
||||
{ return interface_.get_heap_position(_h) != -1; }
|
||||
|
||||
/// insert the entry _h
|
||||
void insert(HeapEntry _h)
|
||||
{
|
||||
push_back(_h);
|
||||
upheap(size()-1);
|
||||
}
|
||||
|
||||
/// get the first entry
|
||||
HeapEntry front() const
|
||||
{
|
||||
assert(!empty());
|
||||
return entry(0);
|
||||
}
|
||||
|
||||
/// delete the first entry
|
||||
void pop_front()
|
||||
{
|
||||
assert(!empty());
|
||||
reset_heap_position(entry(0));
|
||||
if (size() > 1)
|
||||
{
|
||||
entry(0, entry(size()-1));
|
||||
Base::pop_back();
|
||||
downheap(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Base::pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
/// remove an entry
|
||||
void remove(HeapEntry _h)
|
||||
{
|
||||
int pos = interface_.get_heap_position(_h);
|
||||
reset_heap_position(_h);
|
||||
|
||||
assert(pos != -1);
|
||||
assert((unsigned int) pos < size());
|
||||
|
||||
// last item ?
|
||||
if ((unsigned int) pos == size()-1)
|
||||
{
|
||||
Base::pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
entry(pos, entry(size()-1)); // move last elem to pos
|
||||
Base::pop_back();
|
||||
downheap(pos);
|
||||
upheap(pos);
|
||||
}
|
||||
}
|
||||
|
||||
/** update an entry: change the key and update the position to
|
||||
reestablish the heap property.
|
||||
*/
|
||||
void update(HeapEntry _h)
|
||||
{
|
||||
int pos = interface_.get_heap_position(_h);
|
||||
assert(pos != -1);
|
||||
assert((unsigned int)pos < size());
|
||||
downheap(pos);
|
||||
upheap(pos);
|
||||
}
|
||||
|
||||
/// check heap condition
|
||||
bool check()
|
||||
{
|
||||
bool ok(true);
|
||||
unsigned int i, j;
|
||||
for (i=0; i<size(); ++i)
|
||||
{
|
||||
if (((j=left(i))<size()) && interface_.greater(entry(i), entry(j)))
|
||||
{
|
||||
omerr() << "Heap condition violated\n";
|
||||
ok=false;
|
||||
}
|
||||
if (((j=right(i))<size()) && interface_.greater(entry(i), entry(j)))
|
||||
{
|
||||
omerr() << "Heap condition violated\n";
|
||||
ok=false;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Instance of HeapInterface
|
||||
HeapInterface interface_;
|
||||
|
||||
private:
|
||||
// typedef
|
||||
typedef std::vector<HeapEntry> HeapVector;
|
||||
|
||||
|
||||
/// Upheap. Establish heap property.
|
||||
void upheap(unsigned int _idx);
|
||||
|
||||
|
||||
/// Downheap. Establish heap property.
|
||||
void downheap(unsigned int _idx);
|
||||
|
||||
|
||||
/// Get the entry at index _idx
|
||||
inline HeapEntry entry(unsigned int _idx) const
|
||||
{
|
||||
assert(_idx < size());
|
||||
return (Base::operator[](_idx));
|
||||
}
|
||||
|
||||
|
||||
/// Set entry _h to index _idx and update _h's heap position.
|
||||
inline void entry(unsigned int _idx, HeapEntry _h)
|
||||
{
|
||||
assert(_idx < size());
|
||||
Base::operator[](_idx) = _h;
|
||||
interface_.set_heap_position(_h, _idx);
|
||||
}
|
||||
|
||||
|
||||
/// Get parent's index
|
||||
inline unsigned int parent(unsigned int _i) { return (_i-1)>>1; }
|
||||
/// Get left child's index
|
||||
inline unsigned int left(unsigned int _i) { return (_i<<1)+1; }
|
||||
/// Get right child's index
|
||||
inline unsigned int right(unsigned int _i) { return (_i<<1)+2; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//== IMPLEMENTATION ==========================================================
|
||||
|
||||
|
||||
template <class HeapEntry, class HeapInterface>
|
||||
void
|
||||
HeapT<HeapEntry, HeapInterface>::
|
||||
upheap(unsigned int _idx)
|
||||
{
|
||||
HeapEntry h = entry(_idx);
|
||||
unsigned int parentIdx;
|
||||
|
||||
while ((_idx>0) &&
|
||||
interface_.less(h, entry(parentIdx=parent(_idx))))
|
||||
{
|
||||
entry(_idx, entry(parentIdx));
|
||||
_idx = parentIdx;
|
||||
}
|
||||
|
||||
entry(_idx, h);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
template <class HeapEntry, class HeapInterface>
|
||||
void
|
||||
HeapT<HeapEntry, HeapInterface>::
|
||||
downheap(unsigned int _idx)
|
||||
{
|
||||
HeapEntry h = entry(_idx);
|
||||
unsigned int childIdx;
|
||||
unsigned int s = size();
|
||||
|
||||
while(_idx < s)
|
||||
{
|
||||
childIdx = left(_idx);
|
||||
if (childIdx >= s) break;
|
||||
|
||||
if ((childIdx+1 < s) &&
|
||||
(interface_.less(entry(childIdx+1), entry(childIdx))))
|
||||
++childIdx;
|
||||
|
||||
if (interface_.less(h, entry(childIdx))) break;
|
||||
|
||||
entry(_idx, entry(childIdx));
|
||||
_idx = childIdx;
|
||||
}
|
||||
|
||||
entry(_idx, h);
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
} // END_NS_UTILS
|
||||
} // END_NS_OPENMESH
|
||||
//=============================================================================
|
||||
#endif // OSG_HEAP_HH defined
|
||||
//=============================================================================
|
||||
|
||||
222
Tools/Utils/MeshCheckerT.cc
Normal file
222
Tools/Utils/MeshCheckerT.cc
Normal file
@@ -0,0 +1,222 @@
|
||||
//=============================================================================
|
||||
//
|
||||
// OpenMesh
|
||||
// Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen
|
||||
// www.openmesh.org
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// License
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, version 2.1.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// $Revision: 2433 $
|
||||
// $Date: 2008-08-27 13:43:05 +0200 (Mi, 27. Aug 2008) $
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
|
||||
#define OPENMESH_MESHCHECKER_C
|
||||
|
||||
|
||||
//== INCLUDES =================================================================
|
||||
|
||||
|
||||
#include <OpenMesh/Tools/Utils/MeshCheckerT.hh>
|
||||
|
||||
|
||||
//== NAMESPACES ==============================================================
|
||||
|
||||
|
||||
namespace OpenMesh {
|
||||
namespace Utils {
|
||||
|
||||
//== IMPLEMENTATION ==========================================================
|
||||
|
||||
|
||||
template <class Mesh>
|
||||
bool
|
||||
MeshCheckerT<Mesh>::
|
||||
check(unsigned int _targets, std::ostream& _os)
|
||||
{
|
||||
bool ok(true);
|
||||
|
||||
|
||||
|
||||
//--- vertex checks ---
|
||||
|
||||
if (_targets & CHECK_VERTICES)
|
||||
{
|
||||
typename Mesh::ConstVertexIter v_it(mesh_.vertices_begin()),
|
||||
v_end(mesh_.vertices_end());
|
||||
typename Mesh::VertexHandle vh;
|
||||
typename Mesh::ConstVertexVertexIter vv_it;
|
||||
typename Mesh::HalfedgeHandle heh;
|
||||
unsigned int count;
|
||||
const unsigned int max_valence(10000);
|
||||
|
||||
|
||||
for (; v_it != v_end; ++v_it)
|
||||
{
|
||||
if (!is_deleted(v_it))
|
||||
{
|
||||
vh = v_it.handle();
|
||||
|
||||
|
||||
/* The outgoing halfedge of a boundary vertex has to be a
|
||||
boundary halfedge */
|
||||
heh = mesh_.halfedge_handle(vh);
|
||||
if (heh.is_valid() && !mesh_.is_boundary(heh))
|
||||
{
|
||||
for (typename Mesh::ConstVertexOHalfedgeIter vh_it(mesh_, vh);
|
||||
vh_it; ++vh_it)
|
||||
{
|
||||
if (mesh_.is_boundary(vh_it.handle()))
|
||||
{
|
||||
_os << "MeshChecker: vertex " << vh
|
||||
<< ": outgoing halfedge not on boundary error\n";
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// outgoing halfedge has to refer back to vertex
|
||||
if (mesh_.halfedge_handle(vh).is_valid() &&
|
||||
mesh_.from_vertex_handle(mesh_.halfedge_handle(vh)) != vh)
|
||||
{
|
||||
_os << "MeshChecker: vertex " << vh
|
||||
<< ": outgoing halfedge does not reference vertex\n";
|
||||
ok = false;
|
||||
}
|
||||
|
||||
|
||||
// check whether circulators are still in order
|
||||
vv_it = mesh_.cvv_iter(vh);
|
||||
for (count=0; vv_it && (count < max_valence); ++vv_it, ++count) {};
|
||||
if (count == max_valence)
|
||||
{
|
||||
_os << "MeshChecker: vertex " << vh
|
||||
<< ": ++circulator problem, one ring corrupt\n";
|
||||
ok = false;
|
||||
}
|
||||
vv_it = mesh_.cvv_iter(vh);
|
||||
for (count=0; vv_it && (count < max_valence); --vv_it, ++count) {};
|
||||
if (count == max_valence)
|
||||
{
|
||||
_os << "MeshChecker: vertex " << vh
|
||||
<< ": --circulator problem, one ring corrupt\n";
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//--- halfedge checks ---
|
||||
|
||||
if (_targets & CHECK_EDGES)
|
||||
{
|
||||
typename Mesh::ConstHalfedgeIter h_it(mesh_.halfedges_begin()),
|
||||
h_end(mesh_.halfedges_end());
|
||||
typename Mesh::HalfedgeHandle hh, hstart, hhh;
|
||||
unsigned int count, n_halfedges = 2*mesh_.n_edges();
|
||||
|
||||
for (; h_it != h_end; ++h_it)
|
||||
{
|
||||
if (!is_deleted(mesh_.edge_handle(h_it.handle())))
|
||||
{
|
||||
hh = h_it.handle();
|
||||
|
||||
|
||||
// degenerated halfedge ?
|
||||
if (mesh_.from_vertex_handle(hh) == mesh_.to_vertex_handle(hh))
|
||||
{
|
||||
_os << "MeshChecker: halfedge " << hh
|
||||
<< ": to-vertex == from-vertex\n";
|
||||
ok = false;
|
||||
}
|
||||
|
||||
|
||||
// next <-> prev check
|
||||
if (mesh_.next_halfedge_handle(mesh_.prev_halfedge_handle(hh)) != hh)
|
||||
{
|
||||
_os << "MeshChecker: halfedge " << hh
|
||||
<< ": prev->next != this\n";
|
||||
ok = false;
|
||||
}
|
||||
|
||||
|
||||
// halfedges should form a cycle
|
||||
count=0; hstart=hhh=hh;
|
||||
do
|
||||
{
|
||||
hhh = mesh_.next_halfedge_handle(hhh);
|
||||
++count;
|
||||
} while (hhh != hstart && count < n_halfedges);
|
||||
|
||||
if (count == n_halfedges)
|
||||
{
|
||||
_os << "MeshChecker: halfedges starting from " << hh
|
||||
<< " do not form a cycle\n";
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//--- face checks ---
|
||||
|
||||
if (_targets & CHECK_FACES)
|
||||
{
|
||||
typename Mesh::ConstFaceIter f_it(mesh_.faces_begin()),
|
||||
f_end(mesh_.faces_end());
|
||||
typename Mesh::FaceHandle fh;
|
||||
typename Mesh::ConstFaceHalfedgeIter fh_it;
|
||||
|
||||
for (; f_it != f_end; ++f_it)
|
||||
{
|
||||
if (!is_deleted(f_it))
|
||||
{
|
||||
fh = f_it.handle();
|
||||
|
||||
for (fh_it=mesh_.cfh_iter(fh); fh_it; ++fh_it)
|
||||
{
|
||||
if (mesh_.face_handle(fh_it.handle()) != fh)
|
||||
{
|
||||
_os << "MeshChecker: face " << fh
|
||||
<< ": its halfedge does not reference face\n";
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
} // naespace Utils
|
||||
} // namespace OpenMesh
|
||||
//=============================================================================
|
||||
114
Tools/Utils/MeshCheckerT.hh
Normal file
114
Tools/Utils/MeshCheckerT.hh
Normal file
@@ -0,0 +1,114 @@
|
||||
//=============================================================================
|
||||
//
|
||||
// OpenMesh
|
||||
// Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen
|
||||
// www.openmesh.org
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// License
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, version 2.1.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// $Revision: 1802 $
|
||||
// $Date: 2008-05-19 11:55:07 +0200 (Mo, 19. Mai 2008) $
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
|
||||
#ifndef OPENMESH_MESHCHECKER_HH
|
||||
#define OPENMESH_MESHCHECKER_HH
|
||||
|
||||
|
||||
//== INCLUDES =================================================================
|
||||
|
||||
|
||||
#include <OpenMesh/Core/System/config.h>
|
||||
#include <OpenMesh/Core/System/omstream.hh>
|
||||
#include <OpenMesh/Core/Utils/GenProg.hh>
|
||||
#include <OpenMesh/Core/Mesh/Attributes.hh>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
//== NAMESPACES ===============================================================
|
||||
|
||||
|
||||
namespace OpenMesh {
|
||||
namespace Utils {
|
||||
|
||||
//== CLASS DEFINITION =========================================================
|
||||
|
||||
|
||||
/** Check integrity of mesh.
|
||||
*
|
||||
* This class provides several functions to check the integrity of a mesh.
|
||||
*/
|
||||
template <class Mesh>
|
||||
class MeshCheckerT
|
||||
{
|
||||
public:
|
||||
|
||||
/// constructor
|
||||
MeshCheckerT(const Mesh& _mesh) : mesh_(_mesh) {}
|
||||
|
||||
/// destructor
|
||||
~MeshCheckerT() {}
|
||||
|
||||
|
||||
/// what should be checked?
|
||||
enum CheckTargets
|
||||
{
|
||||
CHECK_EDGES = 1,
|
||||
CHECK_VERTICES = 2,
|
||||
CHECK_FACES = 4,
|
||||
CHECK_ALL = 255,
|
||||
};
|
||||
|
||||
|
||||
/// check it, return true iff ok
|
||||
bool check( unsigned int _targets=CHECK_ALL,
|
||||
std::ostream& _os= omerr());
|
||||
|
||||
|
||||
private:
|
||||
|
||||
bool is_deleted(typename Mesh::VertexHandle _vh)
|
||||
{ return (mesh_.has_vertex_status() ? mesh_.status(_vh).deleted() : false); }
|
||||
|
||||
bool is_deleted(typename Mesh::EdgeHandle _eh)
|
||||
{ return (mesh_.has_edge_status() ? mesh_.status(_eh).deleted() : false); }
|
||||
|
||||
bool is_deleted(typename Mesh::FaceHandle _fh)
|
||||
{ return (mesh_.has_face_status() ? mesh_.status(_fh).deleted() : false); }
|
||||
|
||||
|
||||
// ref to mesh
|
||||
const Mesh& mesh_;
|
||||
};
|
||||
|
||||
|
||||
//=============================================================================
|
||||
} // namespace Utils
|
||||
} // namespace OpenMesh
|
||||
//=============================================================================
|
||||
#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_MESHCHECKER_C)
|
||||
#define OPENMESH_MESHCHECKER_TEMPLATES
|
||||
#include "MeshCheckerT.cc"
|
||||
#endif
|
||||
//=============================================================================
|
||||
#endif // OPENMESH_MESHCHECKER_HH defined
|
||||
//=============================================================================
|
||||
|
||||
136
Tools/Utils/NumLimitsT.hh
Normal file
136
Tools/Utils/NumLimitsT.hh
Normal file
@@ -0,0 +1,136 @@
|
||||
//=============================================================================
|
||||
//
|
||||
// OpenMesh
|
||||
// Copyright (C) 2003 by Computer Graphics Group, RWTH Aachen
|
||||
// www.openmesh.org
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// License
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, version 2.1.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// $Revision: 4254 $
|
||||
// $Date: 2009-01-12 14:44:00 +0100 (Mo, 12. Jan 2009) $
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
/** \file NumLimitsT.hh
|
||||
Temporary solution until std::numeric_limits is standard.
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// CLASS NumLimitsT
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef OPENMESH_UTILS_NUMLIMITS_HH
|
||||
#define OPENMESH_UTILS_NUMLIMITS_HH
|
||||
|
||||
|
||||
//== INCLUDES =================================================================
|
||||
|
||||
#include "Config.hh"
|
||||
#include <limits.h>
|
||||
#include <float.h>
|
||||
|
||||
|
||||
//== NAMESPEACES ==============================================================
|
||||
|
||||
namespace OpenMesh { // BEGIN_NS_OPENMESH
|
||||
namespace Utils { // BEGIN_NS_UTILS
|
||||
|
||||
|
||||
//== CLASS DEFINITION =========================================================
|
||||
|
||||
|
||||
/** \class NumLimitsT NumLimitsT.hh <OpenMesh/Utils/NumLimitsT.hh
|
||||
|
||||
This class provides the maximum and minimum values a certain
|
||||
scalar type (\cint, \c float, or \double) can store. You can
|
||||
use it like this:
|
||||
\code
|
||||
#include <OpenMesh/Utils/NumLimitsT.hh>
|
||||
|
||||
int float_min = OpenMesh::NumLimitsT<float>::min();
|
||||
float double_max = OpenMesh::NumLimitsT<double>::max();
|
||||
\endcode
|
||||
|
||||
\note This functionality should be provided by
|
||||
std::numeric_limits. This template does not exist on gcc <=
|
||||
2.95.3. The class template NumLimitsT is just a workaround.
|
||||
**/
|
||||
template <typename Scalar>
|
||||
class NumLimitsT
|
||||
{
|
||||
public:
|
||||
/// Return the smallest \em absolte value a scalar type can store.
|
||||
static inline Scalar min() { return 0; }
|
||||
/// Return the maximum \em absolte value a scalar type can store.
|
||||
static inline Scalar max() { return 0; }
|
||||
|
||||
static inline bool is_float() { return false; }
|
||||
static inline bool is_integer() { return !NumLimitsT<Scalar>::is_float(); }
|
||||
static inline bool is_signed() { return true; }
|
||||
};
|
||||
|
||||
// is_float
|
||||
|
||||
template<>
|
||||
inline bool NumLimitsT<float>::is_float() { return true; }
|
||||
|
||||
template<>
|
||||
inline bool NumLimitsT<double>::is_float() { return true; }
|
||||
|
||||
template<>
|
||||
inline bool NumLimitsT<long double>::is_float() { return true; }
|
||||
|
||||
// is_signed
|
||||
|
||||
template<>
|
||||
inline bool NumLimitsT<unsigned char>::is_signed() { return false; }
|
||||
|
||||
template<>
|
||||
inline bool NumLimitsT<unsigned short>::is_signed() { return false; }
|
||||
|
||||
template<>
|
||||
inline bool NumLimitsT<unsigned int>::is_signed() { return false; }
|
||||
|
||||
template<>
|
||||
inline bool NumLimitsT<unsigned long>::is_signed() { return false; }
|
||||
|
||||
template<>
|
||||
inline bool NumLimitsT<unsigned long long>::is_signed() { return false; }
|
||||
|
||||
// min/max
|
||||
template<> inline int NumLimitsT<int>::min() { return INT_MIN; }
|
||||
template<> inline int NumLimitsT<int>::max() { return INT_MAX; }
|
||||
|
||||
template<> inline float NumLimitsT<float>::min() { return FLT_MIN; }
|
||||
template<> inline float NumLimitsT<float>::max() { return FLT_MAX; }
|
||||
|
||||
template<> inline double NumLimitsT<double>::min() { return DBL_MIN; }
|
||||
template<> inline double NumLimitsT<double>::max() { return DBL_MAX; }
|
||||
|
||||
|
||||
//=============================================================================
|
||||
} // END_NS_UTILS
|
||||
} // END_NS_OPENMESH
|
||||
//=============================================================================
|
||||
#endif // OPENMESH_NUMLIMITS_HH defined
|
||||
//=============================================================================
|
||||
|
||||
253
Tools/Utils/StripifierT.cc
Normal file
253
Tools/Utils/StripifierT.cc
Normal file
@@ -0,0 +1,253 @@
|
||||
//=============================================================================
|
||||
//
|
||||
// OpenMesh
|
||||
// Copyright (C) 2001-2003 by Computer Graphics Group, RWTH Aachen
|
||||
// www.openmesh.org
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// License
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, version 2.1.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// $Revision: 1802 $
|
||||
// $Date: 2008-05-19 11:55:07 +0200 (Mo, 19. Mai 2008) $
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// CLASS StripifierT - IMPLEMENTATION
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#define OPENMESH_STRIPIFIERT_C
|
||||
|
||||
//== INCLUDES =================================================================
|
||||
|
||||
#include <OpenMesh/Tools/Utils/StripifierT.hh>
|
||||
#include <list>
|
||||
|
||||
|
||||
//== NAMESPACES ===============================================================
|
||||
|
||||
namespace OpenMesh {
|
||||
|
||||
|
||||
//== IMPLEMENTATION ==========================================================
|
||||
|
||||
|
||||
template <class Mesh>
|
||||
unsigned int
|
||||
StripifierT<Mesh>::
|
||||
stripify()
|
||||
{
|
||||
// preprocess: add new properties
|
||||
mesh_.add_property( processed_ );
|
||||
mesh_.add_property( used_ );
|
||||
mesh_.request_face_status();
|
||||
|
||||
|
||||
// build strips
|
||||
clear();
|
||||
build_strips();
|
||||
|
||||
|
||||
// postprocess: remove properties
|
||||
//mesh_.remove_property(processed_);
|
||||
//mesh_.remove_property(used_);
|
||||
//mesh_.release_face_status();
|
||||
|
||||
|
||||
return n_strips();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
template <class Mesh>
|
||||
void
|
||||
StripifierT<Mesh>::
|
||||
build_strips()
|
||||
{
|
||||
Strip experiments[3];
|
||||
typename Mesh::HalfedgeHandle h[3];
|
||||
unsigned int best_idx, best_length, length;
|
||||
FaceHandles faces[3];
|
||||
typename FaceHandles::iterator fh_it, fh_end;
|
||||
typename Mesh::FaceIter f_it, f_end=mesh_.faces_end();
|
||||
|
||||
|
||||
|
||||
// init faces to be un-processed and un-used
|
||||
// deleted or hidden faces are marked processed
|
||||
if (mesh_.has_face_status())
|
||||
{
|
||||
for (f_it=mesh_.faces_begin(); f_it!=f_end; ++f_it)
|
||||
if (mesh_.status(f_it).hidden() || mesh_.status(f_it).deleted())
|
||||
processed(f_it) = used(f_it) = true;
|
||||
else
|
||||
processed(f_it) = used(f_it) = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (f_it=mesh_.faces_begin(); f_it!=f_end; ++f_it)
|
||||
processed(f_it) = used(f_it) = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (f_it=mesh_.faces_begin(); true; )
|
||||
{
|
||||
// find start face
|
||||
for (; f_it!=f_end; ++f_it)
|
||||
if (!processed(f_it))
|
||||
break;
|
||||
if (f_it==f_end) break; // stop if all have been processed
|
||||
|
||||
|
||||
// collect starting halfedges
|
||||
h[0] = mesh_.halfedge_handle(f_it.handle());
|
||||
h[1] = mesh_.next_halfedge_handle(h[0]);
|
||||
h[2] = mesh_.next_halfedge_handle(h[1]);
|
||||
|
||||
|
||||
// build 3 strips, take best one
|
||||
best_length = best_idx = 0;
|
||||
for (unsigned int i=0; i<3; ++i)
|
||||
{
|
||||
build_strip(h[i], experiments[i], faces[i]);
|
||||
if ((length = experiments[i].size()) > best_length)
|
||||
{
|
||||
best_length = length;
|
||||
best_idx = i;
|
||||
}
|
||||
|
||||
for (fh_it=faces[i].begin(), fh_end=faces[i].end();
|
||||
fh_it!=fh_end; ++fh_it)
|
||||
used(*fh_it) = false;
|
||||
}
|
||||
|
||||
|
||||
// update processed status
|
||||
fh_it = faces[best_idx].begin();
|
||||
fh_end = faces[best_idx].end();
|
||||
for (; fh_it!=fh_end; ++fh_it)
|
||||
processed(*fh_it) = true;
|
||||
|
||||
|
||||
|
||||
// add best strip to strip-list
|
||||
strips_.push_back(experiments[best_idx]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
template <class Mesh>
|
||||
void
|
||||
StripifierT<Mesh>::
|
||||
build_strip(typename Mesh::HalfedgeHandle _start_hh,
|
||||
Strip& _strip,
|
||||
FaceHandles& _faces)
|
||||
{
|
||||
std::list<unsigned int> strip;
|
||||
typename Mesh::HalfedgeHandle hh;
|
||||
typename Mesh::FaceHandle fh;
|
||||
|
||||
|
||||
// reset face list
|
||||
_faces.clear();
|
||||
|
||||
|
||||
// init strip
|
||||
strip.push_back(mesh_.from_vertex_handle(_start_hh).idx());
|
||||
strip.push_back(mesh_.to_vertex_handle(_start_hh).idx());
|
||||
|
||||
|
||||
// walk along the strip: 1st direction
|
||||
hh = mesh_.prev_halfedge_handle(mesh_.opposite_halfedge_handle(_start_hh));
|
||||
while (1)
|
||||
{
|
||||
// go right
|
||||
hh = mesh_.next_halfedge_handle(hh);
|
||||
hh = mesh_.opposite_halfedge_handle(hh);
|
||||
hh = mesh_.next_halfedge_handle(hh);
|
||||
if (mesh_.is_boundary(hh)) break;
|
||||
fh = mesh_.face_handle(hh);
|
||||
if (processed(fh) || used(fh)) break;
|
||||
_faces.push_back(fh);
|
||||
used(fh) = true;
|
||||
strip.push_back(mesh_.to_vertex_handle(hh).idx());
|
||||
|
||||
// go left
|
||||
hh = mesh_.opposite_halfedge_handle(hh);
|
||||
hh = mesh_.next_halfedge_handle(hh);
|
||||
if (mesh_.is_boundary(hh)) break;
|
||||
fh = mesh_.face_handle(hh);
|
||||
if (processed(fh) || used(fh)) break;
|
||||
_faces.push_back(fh);
|
||||
used(fh) = true;
|
||||
strip.push_back(mesh_.to_vertex_handle(hh).idx());
|
||||
}
|
||||
|
||||
|
||||
// walk along the strip: 2nd direction
|
||||
bool flip(false);
|
||||
hh = mesh_.prev_halfedge_handle(_start_hh);
|
||||
while (1)
|
||||
{
|
||||
// go right
|
||||
hh = mesh_.next_halfedge_handle(hh);
|
||||
hh = mesh_.opposite_halfedge_handle(hh);
|
||||
hh = mesh_.next_halfedge_handle(hh);
|
||||
if (mesh_.is_boundary(hh)) break;
|
||||
fh = mesh_.face_handle(hh);
|
||||
if (processed(fh) || used(fh)) break;
|
||||
_faces.push_back(fh);
|
||||
used(fh) = true;
|
||||
strip.push_front(mesh_.to_vertex_handle(hh).idx());
|
||||
flip = true;
|
||||
|
||||
// go left
|
||||
hh = mesh_.opposite_halfedge_handle(hh);
|
||||
hh = mesh_.next_halfedge_handle(hh);
|
||||
if (mesh_.is_boundary(hh)) break;
|
||||
fh = mesh_.face_handle(hh);
|
||||
if (processed(fh) || used(fh)) break;
|
||||
_faces.push_back(fh);
|
||||
used(fh) = true;
|
||||
strip.push_front(mesh_.to_vertex_handle(hh).idx());
|
||||
flip = false;
|
||||
}
|
||||
|
||||
if (flip) strip.push_front(strip.front());
|
||||
|
||||
|
||||
|
||||
// copy final strip to _strip
|
||||
_strip.clear();
|
||||
_strip.reserve(strip.size());
|
||||
std::copy(strip.begin(), strip.end(), std::back_inserter(_strip));
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
} // namespace OpenMesh
|
||||
//=============================================================================
|
||||
141
Tools/Utils/StripifierT.hh
Normal file
141
Tools/Utils/StripifierT.hh
Normal file
@@ -0,0 +1,141 @@
|
||||
//=============================================================================
|
||||
//
|
||||
// OpenMesh
|
||||
// Copyright (C) 2001-2003 by Computer Graphics Group, RWTH Aachen
|
||||
// www.openmesh.org
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// License
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation, version 2.1.
|
||||
//
|
||||
// This library 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
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// $Revision: 1802 $
|
||||
// $Date: 2008-05-19 11:55:07 +0200 (Mo, 19. Mai 2008) $
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// CLASS StripifierT
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
|
||||
#ifndef OPENMESH_STRIPIFIERT_HH
|
||||
#define OPENMESH_STRIPIFIERT_HH
|
||||
|
||||
|
||||
//== INCLUDES =================================================================
|
||||
|
||||
#include <vector>
|
||||
#include <OpenMesh/Core/Utils/Property.hh>
|
||||
|
||||
|
||||
//== FORWARDDECLARATIONS ======================================================
|
||||
|
||||
|
||||
//== NAMESPACES ===============================================================
|
||||
|
||||
namespace OpenMesh {
|
||||
|
||||
|
||||
//== CLASS DEFINITION =========================================================
|
||||
|
||||
|
||||
|
||||
|
||||
/** \class StripifierT StripifierT.hh <OpenMesh/Tools/Utils/StripifierT.hh>
|
||||
This class decomposes a triangle mesh into several triangle strips.
|
||||
*/
|
||||
|
||||
template <class Mesh>
|
||||
class StripifierT
|
||||
{
|
||||
public:
|
||||
|
||||
typedef unsigned int Index;
|
||||
typedef std::vector<Index> Strip;
|
||||
typedef typename Strip::const_iterator IndexIterator;
|
||||
typedef std::vector<Strip> Strips;
|
||||
typedef typename Strips::const_iterator StripsIterator;
|
||||
|
||||
|
||||
/// Default constructor
|
||||
StripifierT(Mesh& _mesh) : mesh_(_mesh) {}
|
||||
|
||||
/// Destructor
|
||||
~StripifierT() {}
|
||||
|
||||
|
||||
/// Compute triangle strips, returns number of strips
|
||||
unsigned int stripify();
|
||||
|
||||
/// delete all strips
|
||||
void clear() { Strips().swap(strips_); }
|
||||
|
||||
/// returns number of strips
|
||||
unsigned int n_strips() const { return strips_.size(); }
|
||||
|
||||
/// are strips computed?
|
||||
bool is_valid() const { return !strips_.empty(); }
|
||||
|
||||
/// Access strips
|
||||
StripsIterator begin() const { return strips_.begin(); }
|
||||
/// Access strips
|
||||
StripsIterator end() const { return strips_.end(); }
|
||||
|
||||
|
||||
private:
|
||||
|
||||
typedef std::vector<typename Mesh::FaceHandle> FaceHandles;
|
||||
|
||||
|
||||
/// this method does the main work
|
||||
void build_strips();
|
||||
|
||||
/// build a strip from a given halfedge (in both directions)
|
||||
void build_strip(typename Mesh::HalfedgeHandle _start_hh,
|
||||
Strip& _strip,
|
||||
FaceHandles& _faces);
|
||||
|
||||
FPropHandleT<bool>::reference processed(typename Mesh::FaceHandle _fh) {
|
||||
return mesh_.property(processed_, _fh);
|
||||
}
|
||||
FPropHandleT<bool>::reference used(typename Mesh::FaceHandle _fh) {
|
||||
return mesh_.property(used_, _fh);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
Mesh& mesh_;
|
||||
Strips strips_;
|
||||
FPropHandleT<bool> processed_, used_;
|
||||
};
|
||||
|
||||
|
||||
//=============================================================================
|
||||
} // namespace OpenMesh
|
||||
//=============================================================================
|
||||
#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_STRIPIFIERT_C)
|
||||
#define OPENMESH_STRIPIFIERT_TEMPLATES
|
||||
#include "StripifierT.cc"
|
||||
#endif
|
||||
//=============================================================================
|
||||
#endif // OPENMESH_STRIPIFIERT_HH defined
|
||||
//=============================================================================
|
||||
330
Tools/Utils/TestingFramework.hh
Normal file
330
Tools/Utils/TestingFramework.hh
Normal file
@@ -0,0 +1,330 @@
|
||||
// ============================================================================
|
||||
// $Id: TestingFramework.hh,v 1.1.1.1 2006-10-25 16:14:15 habbecke Exp $
|
||||
// ----------------------------------------------------------------------------
|
||||
#ifndef TESTINGFRAMEWORK_HH
|
||||
#define TESTINGFRAMEWORK_HH
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/** \file TestingFramework.hh
|
||||
This file contains a little framework for test programms
|
||||
*/
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Config.hh"
|
||||
#include <iosfwd>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
#include <OpenMesh/Core/Utils/Noncopyable.hh>
|
||||
|
||||
// ------------------------------------------------------------- namespace ----
|
||||
|
||||
namespace OpenMesh { // BEGIN_NS_OPENMESH
|
||||
namespace Utils { // BEGIN_NS_UTILS
|
||||
|
||||
|
||||
// ----------------------------------------------------------------- class ----
|
||||
//
|
||||
// Usage Example
|
||||
//
|
||||
// #include <iostream>
|
||||
// #include <.../TestingFramework.hh>
|
||||
//
|
||||
// struct test_func : public TestingFramework::TestFunc
|
||||
// {
|
||||
// typedef test_func Self;
|
||||
//
|
||||
// // define ctor and copy-ctor
|
||||
// test_func( TestingFramework& _th, std::string _n ) : TestingFramework::TestFunc( _th, _n ) { }
|
||||
// test_func( Self& _cpy ) : TestingFramework::TestFunc(_cpy) { }
|
||||
//
|
||||
// // overload body()
|
||||
// void body()
|
||||
// {
|
||||
//
|
||||
// // Do the tests
|
||||
// // direct call to verify
|
||||
// verify( testResult, expectedResult, "additional information" );
|
||||
//
|
||||
// // or use the define TH_VERIFY. The test-expression will be used as the message string
|
||||
// TH_VERIFY( testResult, expectedResult );
|
||||
//
|
||||
// ...
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// int main(...)
|
||||
// {
|
||||
// TestingFramework testSuite(std::cout); // send output to stdout
|
||||
//
|
||||
// new test_func(testSuite); // create new test instance. It registers with testSuite.
|
||||
// return testSuite.run();
|
||||
// }
|
||||
//
|
||||
|
||||
//
|
||||
#define TH_VERIFY( expr, expt ) \
|
||||
verify( expr, expt, #expr )
|
||||
|
||||
//
|
||||
#define TH_VERIFY_X( expr, expt ) \
|
||||
verify_x( expr, expt, #expr )
|
||||
|
||||
/** Helper class for test programms.
|
||||
\internal
|
||||
*/
|
||||
class TestingFramework : Noncopyable
|
||||
{
|
||||
public:
|
||||
|
||||
typedef TestingFramework Self;
|
||||
typedef std::logic_error verify_error;
|
||||
|
||||
#ifndef DOXY_IGNORE_THIS
|
||||
class TestFunc
|
||||
{
|
||||
public:
|
||||
TestFunc( TestingFramework& _th, const std::string& _n )
|
||||
: th_(_th), name_(_n)
|
||||
{
|
||||
th_.reg(this);
|
||||
}
|
||||
|
||||
virtual ~TestFunc()
|
||||
{ }
|
||||
|
||||
void operator() ( void )
|
||||
{
|
||||
prolog();
|
||||
try
|
||||
{
|
||||
body();
|
||||
}
|
||||
catch( std::exception& x )
|
||||
{
|
||||
std::cerr << "<<Error>>: Cannot proceed test due to failure of last"
|
||||
<< " test: " << x.what() << std::endl;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
std::cerr << "Fatal: cannot proceed test due to unknown error!"
|
||||
<< std::endl;
|
||||
}
|
||||
epilog();
|
||||
}
|
||||
|
||||
const TestingFramework& testHelper() const { return th_; }
|
||||
|
||||
protected:
|
||||
|
||||
virtual void prolog(void)
|
||||
{
|
||||
begin(name_);
|
||||
}
|
||||
|
||||
virtual void body(void) = 0;
|
||||
|
||||
virtual void epilog(void)
|
||||
{
|
||||
end();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
TestingFramework& testHelper() { return th_; }
|
||||
|
||||
TestFunc( const TestFunc& _cpy ) : th_(_cpy.th_), name_(_cpy.name_) { }
|
||||
|
||||
|
||||
// Use the following method in prolog()
|
||||
TestFunc& begin(std::string _title, const std::string& _info = "")
|
||||
{ th_.begin(_title,_info); return *this; }
|
||||
|
||||
|
||||
// Use the following method in epilog()
|
||||
TestFunc& end(void)
|
||||
{ th_.end(); return *this; }
|
||||
|
||||
|
||||
// Use the followin methods in body()
|
||||
|
||||
template <typename ValueType>
|
||||
bool
|
||||
verify( const ValueType& _rc, const ValueType& _expected,
|
||||
std::string _info )
|
||||
{ return th_.verify( _rc, _expected, _info ); }
|
||||
|
||||
template <typename ValueType>
|
||||
void
|
||||
verify_x( const ValueType& _rc, const ValueType& _expected,
|
||||
std::string _info )
|
||||
{
|
||||
if ( !verify(_rc, _expected, _info) )
|
||||
throw verify_error(_info);
|
||||
}
|
||||
|
||||
TestFunc& info(const std::string& _info)
|
||||
{ th_.info(_info); return *this; }
|
||||
|
||||
TestFunc& info(const std::ostringstream& _ostr)
|
||||
{ th_.info(_ostr); return *this; }
|
||||
|
||||
private:
|
||||
TestFunc();
|
||||
|
||||
protected:
|
||||
TestingFramework& th_;
|
||||
std::string name_;
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef TestFunc* TestFuncPtr;
|
||||
typedef std::vector<TestFuncPtr> TestSet;
|
||||
|
||||
public:
|
||||
|
||||
TestingFramework(std::ostream& _os)
|
||||
: errTotal_(0), errCount_(0),
|
||||
verifyTotal_(0), verifyCount_(0),
|
||||
testTotal_(0), testCount_(0),
|
||||
os_(_os)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
|
||||
#ifndef DOXY_IGNORE_THIS
|
||||
struct TestDeleter
|
||||
{
|
||||
void operator() (TestFuncPtr _tfptr) { delete _tfptr; }
|
||||
};
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
virtual ~TestingFramework()
|
||||
{
|
||||
std::for_each(tests_.begin(), tests_.end(), TestDeleter() );
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
template <typename ValueType>
|
||||
bool verify(const ValueType& _rc,
|
||||
const ValueType& _expected,
|
||||
const std::string& _info)
|
||||
{
|
||||
++verifyTotal_;
|
||||
if ( _rc == _expected )
|
||||
{
|
||||
os_ << " " << _info << ", result: " << _rc << ", OK!" << std::endl;
|
||||
return true;
|
||||
}
|
||||
++errTotal_;
|
||||
os_ << " " << _info << ", result: " << _rc << " != " << _expected
|
||||
<< " <<ERROR>>" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
Self& begin(std::string _title, const std::string& _info = "")
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
|
||||
testTitle_ = _title;
|
||||
errCount_ = errTotal_;
|
||||
++testTotal_;
|
||||
|
||||
ostr << _title;
|
||||
if ( !_info.empty() )
|
||||
ostr << " ["<< _info << "]";
|
||||
testTitle_ = ostr.str();
|
||||
os_ << "Begin " << testTitle_ << std::endl;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Self& end()
|
||||
{
|
||||
if (errorCount()==0)
|
||||
++testCount_;
|
||||
|
||||
os_ << "End " << testTitle_ << ": " << errorCount() << " Error(s)." << std::endl;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Self& info(const std::string& _info)
|
||||
{
|
||||
os_ << " + " << _info << std::endl;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Self& info(const std::ostringstream& _ostr)
|
||||
{
|
||||
os_ << " + " << _ostr.str() << std::endl;
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t errorTotal() const { return errTotal_; }
|
||||
size_t errorCount() const { return errTotal_ - errCount_; }
|
||||
size_t verifyTotal() const { return verifyTotal_; }
|
||||
size_t verifyCount() const { return verifyTotal_ - verifyCount_; }
|
||||
size_t goodTotal() const { return verifyTotal() - errorTotal(); }
|
||||
size_t goodCount() const { return verifyCount() - errorCount(); }
|
||||
|
||||
size_t testTotal() const { return testTotal_; }
|
||||
size_t testCount() const { return testCount_; }
|
||||
|
||||
public:
|
||||
|
||||
int run(void)
|
||||
{
|
||||
os_ << "Test started\n";
|
||||
TestRunner executer;
|
||||
std::for_each(tests_.begin(), tests_.end(), executer );
|
||||
os_ << std::endl;
|
||||
os_ << "All tests completed" << std::endl
|
||||
<< " #Tests: " << testCount() << "/" << testTotal() << std::endl
|
||||
<< " #Errors: " << errorTotal() << "/" << verifyTotal() << std::endl;
|
||||
return errorTotal();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
#ifndef DOXY_IGNORE_THIS
|
||||
struct TestRunner
|
||||
{
|
||||
void operator() (TestFuncPtr _tfptr) { (*_tfptr)(); }
|
||||
};
|
||||
#endif
|
||||
|
||||
int reg(TestFuncPtr _tfptr)
|
||||
{
|
||||
tests_.push_back(_tfptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
friend class TestFunc;
|
||||
|
||||
private:
|
||||
|
||||
size_t errTotal_;
|
||||
size_t errCount_;
|
||||
size_t verifyTotal_;
|
||||
size_t verifyCount_;
|
||||
size_t testTotal_; // #Tests
|
||||
size_t testCount_; // #Tests ohne Fehler
|
||||
|
||||
std::string testTitle_;
|
||||
std::ostream& os_;
|
||||
|
||||
TestSet tests_;
|
||||
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
} // END_NS_UTILS
|
||||
} // END_NS_OPENMESH
|
||||
// ============================================================================
|
||||
#endif // TESTINGFRMEWORK_HH
|
||||
// ============================================================================
|
||||
397
Tools/Utils/Timer.cc
Normal file
397
Tools/Utils/Timer.cc
Normal file
@@ -0,0 +1,397 @@
|
||||
// ============================================================================
|
||||
// $Id: Timer.cc,v 1.1.1.1 2006-10-25 16:14:15 habbecke Exp $
|
||||
// ----------------------------------------------------------------------------
|
||||
#ifndef DOXY_IGNORE_THIS
|
||||
// ----------------------------------------------------------------------------
|
||||
#include <OpenMesh/Core/System/config.h>
|
||||
#if defined(OM_CC_MIPS)
|
||||
# include <math.h>
|
||||
# include <stdio.h>
|
||||
#else
|
||||
# include <cmath>
|
||||
# include <cstdio>
|
||||
#endif
|
||||
#include "Timer.hh"
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// ------------------------------------------------------------- namespace ----
|
||||
|
||||
namespace OpenMesh {
|
||||
namespace Utils {
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
using namespace std;
|
||||
|
||||
// -------------------------------------------------------------- TimerImpl ----
|
||||
// just a base class for the implementation
|
||||
class TimerImpl
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
TimerImpl() { ; }
|
||||
virtual ~TimerImpl() { ; }
|
||||
|
||||
virtual void reset(void) = 0;
|
||||
virtual void start(void) = 0;
|
||||
virtual void stop(void) = 0;
|
||||
virtual void cont(void) = 0;
|
||||
virtual double seconds(void) const = 0;
|
||||
};
|
||||
|
||||
// compiler and os dependent implementation
|
||||
|
||||
// ------------------------------------------------------------- windows 32 ----
|
||||
#if defined(WIN32) && (defined(_MSC_VER) || defined(__INTEL_COMPILER))
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
class TimerImplWin32 : public TimerImpl
|
||||
{
|
||||
protected:
|
||||
LARGE_INTEGER freq_;
|
||||
LARGE_INTEGER count_;
|
||||
LARGE_INTEGER start_;
|
||||
|
||||
public:
|
||||
TimerImplWin32(void);
|
||||
~TimerImplWin32(void) { ; }
|
||||
|
||||
virtual void reset(void);
|
||||
virtual void start(void);
|
||||
virtual void stop(void);
|
||||
virtual void cont(void);
|
||||
virtual double seconds(void) const;
|
||||
};
|
||||
|
||||
TimerImplWin32::TimerImplWin32(void)
|
||||
{
|
||||
if (QueryPerformanceFrequency(&freq_)==FALSE)
|
||||
throw std::runtime_error("Performance counter of of stock!");
|
||||
reset();
|
||||
}
|
||||
|
||||
void TimerImplWin32::reset(void)
|
||||
{
|
||||
memset(&count_,0,sizeof(count_));
|
||||
memset(&start_,0,sizeof(count_));
|
||||
}
|
||||
|
||||
void TimerImplWin32::start(void)
|
||||
{
|
||||
reset();
|
||||
QueryPerformanceCounter(&start_);
|
||||
}
|
||||
|
||||
void TimerImplWin32::stop(void)
|
||||
{
|
||||
LARGE_INTEGER stop_;
|
||||
|
||||
QueryPerformanceCounter(&stop_);
|
||||
count_.QuadPart += stop_.QuadPart - start_.QuadPart;
|
||||
}
|
||||
|
||||
void TimerImplWin32::cont(void)
|
||||
{
|
||||
QueryPerformanceCounter(&start_);
|
||||
}
|
||||
|
||||
double TimerImplWin32::seconds(void) const
|
||||
{
|
||||
return (double)count_.QuadPart/(double)freq_.QuadPart;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------- posix time ----
|
||||
#elif defined(__GNUC__) && defined(__POSIX__)
|
||||
|
||||
# include <time.h>
|
||||
|
||||
template <clockid_t N>
|
||||
class TimerImplPosix : public TimerImpl
|
||||
{
|
||||
public:
|
||||
TimerImplPosix() : id_(N), seconds_(0.0)
|
||||
{ }
|
||||
|
||||
~TimerImplPosix()
|
||||
{ }
|
||||
|
||||
virtual void reset(void) { seconds_ = 0.0; }
|
||||
|
||||
virtual void start(void) { seconds_ = 0.0; clock_gettime( id_, &start_ ); }
|
||||
virtual void stop(void)
|
||||
{
|
||||
timespec stop;
|
||||
clock_gettime( id_, &stop );
|
||||
seconds_ += ( stop.tv_sec - start_.tv_sec );
|
||||
seconds_ += ( (double(stop.tv_nsec-start_.tv_nsec)*1e-9) );
|
||||
}
|
||||
|
||||
virtual void cont(void) { clock_gettime( id_, &start_ ); }
|
||||
|
||||
virtual double seconds() const { return seconds_; }
|
||||
|
||||
protected:
|
||||
clockid_t id_;
|
||||
double seconds_;
|
||||
timespec start_;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------- gettimeofday ----
|
||||
#elif defined(__GNUC__) || (defined(__INTEL_COMPILER) && !defined(WIN32))
|
||||
|
||||
# include <sys/time.h>
|
||||
# include <sys/resource.h>
|
||||
# include <unistd.h>
|
||||
|
||||
class TimerImplGToD: public TimerImpl
|
||||
{
|
||||
public:
|
||||
TimerImplGToD() : seconds_(0.0)
|
||||
{ }
|
||||
|
||||
~TimerImplGToD()
|
||||
{ }
|
||||
|
||||
virtual void reset(void) { seconds_ = 0.0; }
|
||||
virtual void start(void) { seconds_ = 0.0; gettimeofday( &start_, &tz_ ); }
|
||||
|
||||
virtual void stop(void)
|
||||
{
|
||||
gettimeofday( &stop_, &tz_ );
|
||||
|
||||
seconds_ += (double)(stop_.tv_sec - start_.tv_sec);
|
||||
seconds_ += (double)(stop_.tv_usec- start_.tv_usec)*1e-6;
|
||||
}
|
||||
|
||||
virtual void cont(void) { gettimeofday( &start_, &tz_); }
|
||||
|
||||
virtual double seconds() const { return seconds_; }
|
||||
|
||||
private:
|
||||
|
||||
struct timeval start_, stop_;
|
||||
struct timezone tz_;
|
||||
|
||||
double seconds_;
|
||||
};
|
||||
|
||||
|
||||
#else // ---------------------------------------- standard implementation ----
|
||||
|
||||
#include <time.h>
|
||||
|
||||
static const unsigned long clockticks = CLOCKS_PER_SEC;
|
||||
|
||||
class TimerImplStd : public TimerImpl
|
||||
{
|
||||
public:
|
||||
TimerImplStd() : freq_(clockticks) { reset(); }
|
||||
~TimerImplStd() { ; }
|
||||
|
||||
virtual void reset(void) { count_ = 0; }
|
||||
virtual void start(void) { count_ = 0; start_ = clock(); }
|
||||
virtual void stop(void);
|
||||
virtual void cont(void) { start_ = clock(); }
|
||||
virtual double seconds(void) const { return (double)count_/(double)freq_; }
|
||||
|
||||
protected:
|
||||
unsigned long freq_;
|
||||
unsigned long count_;
|
||||
unsigned long start_;
|
||||
};
|
||||
|
||||
void TimerImplStd::stop(void)
|
||||
{
|
||||
unsigned long stop_ = clock();
|
||||
count_ += stop_-start_;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------- Timer ----
|
||||
|
||||
Timer::Timer(void)
|
||||
{
|
||||
#if defined(WIN32) && defined(_MSC_VER)
|
||||
impl_ = new TimerImplWin32;
|
||||
#elif defined(__GNUC__) && defined(__POSIX__)
|
||||
// CLOCK_REALTIME
|
||||
// CLOCK_MONOTONIC - ?
|
||||
// CLOCK_REALTIME_HR - RTlinux
|
||||
// CLOCK_MONOTONIC_HR - ?
|
||||
# if defined(CLOCK_REALTIME_HR)
|
||||
impl_ = new TimerImplPosix<CLOCK_REALTIME_HR>;
|
||||
# else
|
||||
impl_ = new TimerImplPosix<CLOCK_REALTIME>;
|
||||
# endif
|
||||
#elif defined(__GNUC__) || (defined(__INTEL_COMPILER) && !defined(WIN32))
|
||||
impl_ = new TimerImplGToD;
|
||||
#else
|
||||
impl_ = new TimerImplStd;
|
||||
#endif
|
||||
state_ = Stopped;
|
||||
}
|
||||
|
||||
Timer::~Timer(void)
|
||||
{
|
||||
delete impl_;
|
||||
state_ = Stopped;
|
||||
}
|
||||
|
||||
void Timer::reset(void)
|
||||
{
|
||||
state_ = Stopped;
|
||||
impl_->reset();
|
||||
}
|
||||
|
||||
void Timer::start(void)
|
||||
{
|
||||
state_ = Running;
|
||||
impl_->start();
|
||||
}
|
||||
|
||||
void Timer::stop(void)
|
||||
{
|
||||
impl_->stop();
|
||||
state_ = Stopped;
|
||||
}
|
||||
|
||||
void Timer::cont(void)
|
||||
{
|
||||
impl_->cont();
|
||||
state_ = Running;
|
||||
}
|
||||
|
||||
double Timer::seconds(void) const
|
||||
{
|
||||
return state_==Stopped ? impl_->seconds() : 0.0;
|
||||
}
|
||||
|
||||
std::string Timer::as_string(Timer::Format format)
|
||||
{
|
||||
if (state_ == Running)
|
||||
return "Running";
|
||||
return as_string(impl_->seconds(),format);
|
||||
}
|
||||
|
||||
std::string Timer::as_string(double seconds, Timer::Format format)
|
||||
{
|
||||
char string[32];
|
||||
|
||||
double fraction;
|
||||
double integer;
|
||||
unsigned long t;
|
||||
// double rest;
|
||||
short hour,min,sec;
|
||||
bool negative = false;
|
||||
|
||||
if ( seconds < 0 )
|
||||
{
|
||||
negative = true;
|
||||
seconds *= -1;
|
||||
}
|
||||
|
||||
fraction = modf(seconds,&integer);
|
||||
|
||||
t = (unsigned long)integer;
|
||||
|
||||
hour = short( t / 3600L );
|
||||
t %= 3600L;
|
||||
min = short( t / 60L );
|
||||
t %= 60L;
|
||||
sec = short( t );
|
||||
// rest = (double)t + fraction;
|
||||
|
||||
char *ptr = string;
|
||||
if (negative)
|
||||
*ptr++ = '-';
|
||||
|
||||
switch(format)
|
||||
{
|
||||
case Timer::Automatic:
|
||||
if (hour)
|
||||
ptr += sprintf(ptr,"%02dh:",hour);
|
||||
|
||||
if (min)
|
||||
ptr += sprintf(ptr,"%02dm:",min);
|
||||
else if (ptr>string && hour)
|
||||
ptr += sprintf(ptr,"00m:");
|
||||
|
||||
if (sec)
|
||||
ptr += sprintf(ptr,"%02d",sec);
|
||||
else if (ptr>string && min)
|
||||
ptr += sprintf(ptr,"00");
|
||||
|
||||
if (!hour && !min) // higher resolution necessary
|
||||
{
|
||||
if (ptr > string && sec)
|
||||
{
|
||||
sprintf(ptr,".%.3fs",fraction);
|
||||
ptr++;
|
||||
while(*(ptr+2))
|
||||
{
|
||||
*ptr = *(ptr+2);
|
||||
ptr++;
|
||||
}
|
||||
*ptr = '\0';
|
||||
}
|
||||
else if ( fraction * 1e2 > 0.1)
|
||||
sprintf(ptr,"%.3fcs",fraction*1.e2);
|
||||
else if ( fraction * 1e3 > 0.1)
|
||||
sprintf(ptr,"%.3fms",fraction*1.e3);
|
||||
else if ( fraction * 1e6 > 0.1)
|
||||
sprintf(ptr,"%.1f\xb5s",fraction*1.e6);
|
||||
else if ( fraction * 1e9 > 0.1)
|
||||
sprintf(ptr,"%.1fns",fraction*1.e9);
|
||||
else
|
||||
sprintf(ptr,"%.1fps",fraction*1.e12);
|
||||
} else // append a 's' for seconds!
|
||||
{
|
||||
ptr[0] = 's';
|
||||
ptr[1] = '\0';
|
||||
}
|
||||
break;
|
||||
case Timer::Long:
|
||||
ptr += sprintf(ptr,"%02dh:%02dm:%02d",hour,min,sec);
|
||||
sprintf(ptr,".%.12fs",fraction);
|
||||
ptr++;
|
||||
while(*(ptr+2))
|
||||
{
|
||||
*ptr = *(ptr+2);
|
||||
ptr++;
|
||||
}
|
||||
*ptr = '\0';
|
||||
break;
|
||||
case Timer::Hours:
|
||||
sprintf(ptr,"%02dh:%02dm:%02ds",hour,min,sec); break;
|
||||
case Timer::Minutes:
|
||||
ptr += sprintf(ptr,"%02dm:%02d", min, sec);
|
||||
sprintf(ptr,".%.2fs",fraction);
|
||||
ptr++;
|
||||
while(*(ptr+2))
|
||||
{
|
||||
*ptr = *(ptr+2);
|
||||
ptr++;
|
||||
}
|
||||
*ptr = '\0';
|
||||
break;
|
||||
case Timer::Seconds: sprintf(ptr,"%.3fs",seconds); break;
|
||||
case Timer::HSeconds: sprintf(ptr,"%.3fcs",seconds*1e2); break;
|
||||
case Timer::MSeconds: sprintf(ptr,"%.3fms",seconds*1e3); break;
|
||||
case Timer::MicroSeconds: sprintf(ptr,"%.1f\xb5s",seconds*1e6); break;
|
||||
case Timer::NanoSeconds: sprintf(ptr,"%.1fns",seconds*1e9); break;
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
} // END_NS_UTILS
|
||||
} // END_NS_OPENMESH
|
||||
// ----------------------------------------------------------------------------
|
||||
#endif // DOXY_IGNORE_THIS
|
||||
// ============================================================================
|
||||
// end of file Timer.cc
|
||||
// ============================================================================
|
||||
|
||||
169
Tools/Utils/Timer.hh
Normal file
169
Tools/Utils/Timer.hh
Normal file
@@ -0,0 +1,169 @@
|
||||
// ============================================================================
|
||||
// $Id: Timer.hh,v 1.1.1.1 2006-10-25 16:14:15 habbecke Exp $
|
||||
// ----------------------------------------------------------------------------
|
||||
#ifndef TIMER_HH
|
||||
#define TIMER_HH
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/** \file Timer.hh
|
||||
A timer class
|
||||
*/
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <OpenMesh/Core/System/config.hh>
|
||||
//
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#if defined(OM_CC_MIPS)
|
||||
# include <assert.h>
|
||||
#else
|
||||
# include <cassert>
|
||||
#endif
|
||||
|
||||
|
||||
// ------------------------------------------------------------- namespace ----
|
||||
|
||||
namespace OpenMesh {
|
||||
namespace Utils {
|
||||
|
||||
|
||||
// -------------------------------------------------------------- forwards ----
|
||||
|
||||
|
||||
class TimerImpl;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------- class ----
|
||||
|
||||
/** Timer class
|
||||
*/
|
||||
class Timer
|
||||
{
|
||||
public:
|
||||
|
||||
/// Formatting options for member Timer::as_string()
|
||||
enum Format {
|
||||
Automatic,
|
||||
Long,
|
||||
Hours,
|
||||
Minutes,
|
||||
Seconds,
|
||||
HSeconds,
|
||||
MSeconds,
|
||||
MicroSeconds,
|
||||
NanoSeconds
|
||||
};
|
||||
|
||||
Timer(void);
|
||||
~Timer(void);
|
||||
|
||||
/// Returns true if self is in a valid state!
|
||||
bool is_valid() const { return state_!=Invalid; }
|
||||
|
||||
bool is_stopped() const { return state_==Stopped; }
|
||||
|
||||
/// Reset the timer
|
||||
void reset(void);
|
||||
|
||||
/// Start measurement
|
||||
void start(void);
|
||||
|
||||
/// Stop measurement
|
||||
void stop(void);
|
||||
|
||||
/// Continue measurement
|
||||
void cont(void);
|
||||
|
||||
/// Give resolution of timer. Depends on the underlying measurement method.
|
||||
float resolution() const;
|
||||
|
||||
/// Returns measured time in seconds, if the timer is in state 'Stopped'
|
||||
double seconds(void) const;
|
||||
|
||||
/// Returns measured time in hundredth seconds, if the timer is in state 'Stopped'
|
||||
double hseconds(void) const { return seconds()*1e2; }
|
||||
|
||||
/// Returns measured time in milli seconds, if the timer is in state 'Stopped'
|
||||
double mseconds(void) const { return seconds()*1e3; }
|
||||
|
||||
/// Returns measured time in micro seconds, if the timer is in state 'Stopped'
|
||||
double useconds(void) const { return seconds()*1e6; }
|
||||
|
||||
/** Returns the measured time as a string. Use the format flags to specify
|
||||
a wanted resolution.
|
||||
*/
|
||||
std::string as_string(Format format = Automatic);
|
||||
|
||||
/** Returns a given measured time as a string. Use the format flags to
|
||||
specify a wanted resolution.
|
||||
*/
|
||||
static std::string as_string(double seconds, Format format = Automatic);
|
||||
|
||||
public:
|
||||
|
||||
//@{
|
||||
/// Compare timer values
|
||||
bool operator < (const Timer& t2) const
|
||||
{
|
||||
assert( is_stopped() && t2.is_stopped() );
|
||||
return (seconds() < t2.seconds());
|
||||
}
|
||||
|
||||
bool operator > (const Timer& t2) const
|
||||
{
|
||||
assert( is_stopped() && t2.is_stopped() );
|
||||
return (seconds() > t2.seconds());
|
||||
}
|
||||
|
||||
bool operator == (const Timer& t2) const
|
||||
{
|
||||
assert( is_stopped() && t2.is_stopped() );
|
||||
return (seconds() == t2.seconds());
|
||||
}
|
||||
|
||||
bool operator <= (const Timer& t2) const
|
||||
{
|
||||
assert( is_stopped() && t2.is_stopped() );
|
||||
return (seconds() <= t2.seconds());
|
||||
}
|
||||
|
||||
bool operator >=(const Timer& t2) const
|
||||
{
|
||||
assert( is_stopped() && t2.is_stopped() );
|
||||
return (seconds() >= t2.seconds());
|
||||
}
|
||||
//@}
|
||||
|
||||
protected:
|
||||
|
||||
TimerImpl *impl_;
|
||||
|
||||
enum {
|
||||
Invalid = -1,
|
||||
Stopped = 0,
|
||||
Running = 1
|
||||
} state_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/** Write seconds to output stream.
|
||||
* Timer must be stopped before.
|
||||
* \relates Timer
|
||||
*/
|
||||
inline std::ostream& operator << (std::ostream& _o, const Timer& _t)
|
||||
{
|
||||
return (_o << _t.seconds());
|
||||
}
|
||||
|
||||
|
||||
// ============================================================================
|
||||
} // END_NS_UTILS
|
||||
} // END_NS_OPENMESH
|
||||
// ============================================================================
|
||||
#endif
|
||||
// end of Timer.hh
|
||||
// ===========================================================================
|
||||
|
||||
183
Tools/Utils/conio.cc
Normal file
183
Tools/Utils/conio.cc
Normal file
@@ -0,0 +1,183 @@
|
||||
// ============================================================================
|
||||
|
||||
#include <OpenMesh/Core/System/config.hh>
|
||||
#include <OpenMesh/Tools/Utils/conio.hh>
|
||||
|
||||
// ----------------------------------------------------------------- Win32 ----
|
||||
#ifdef WIN32
|
||||
|
||||
#include <conio.h>
|
||||
|
||||
namespace OpenMesh {
|
||||
namespace Utils {
|
||||
|
||||
int kbhit() { return ::kbhit(); }
|
||||
int getch() { return ::getch(); }
|
||||
int getche() { return ::getche(); }
|
||||
|
||||
} // Tools
|
||||
} // AS
|
||||
// ----------------------------------------------------------------- Other ----
|
||||
#else
|
||||
|
||||
// Based on code published by Floyd Davidson in a newsgroup.
|
||||
|
||||
#include <stdio.h> /* stdout, fflush() */
|
||||
#if !defined(POSIX_1003_1_2001)
|
||||
# include <fcntl.h>
|
||||
# include <unistd.h>
|
||||
#else
|
||||
# include <select.h> /* select() */
|
||||
#endif
|
||||
#include <termios.h> /* tcsetattr() */
|
||||
#include <sys/ioctl.h> /* ioctl() */
|
||||
#include <sys/time.h> /* struct timeval */
|
||||
|
||||
namespace OpenMesh {
|
||||
namespace Utils {
|
||||
|
||||
#ifdef CTIME
|
||||
# undef CTIME
|
||||
#endif
|
||||
#define CTIME 1
|
||||
#define CMIN 1
|
||||
|
||||
|
||||
int kbhit(void)
|
||||
{
|
||||
int cnt = 0;
|
||||
int error;
|
||||
static struct termios Otty, Ntty;
|
||||
|
||||
tcgetattr(0, &Otty);
|
||||
Ntty = Otty;
|
||||
|
||||
Ntty.c_iflag = 0; /* input mode */
|
||||
Ntty.c_oflag = 0; /* output mode */
|
||||
Ntty.c_lflag &= ~ICANON; /* raw mode */
|
||||
Ntty.c_cc[VMIN] = CMIN; /* minimum chars to wait for */
|
||||
Ntty.c_cc[VTIME] = CTIME; /* minimum wait time */
|
||||
|
||||
if (0 == (error = tcsetattr(0, TCSANOW, &Ntty)))
|
||||
{
|
||||
struct timeval tv;
|
||||
error += ioctl(0, FIONREAD, &cnt);
|
||||
error += tcsetattr(0, TCSANOW, &Otty);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 100; /* insert at least a minimal delay */
|
||||
select(1, NULL, NULL, NULL, &tv);
|
||||
}
|
||||
return (error == 0 ? cnt : -1 );
|
||||
}
|
||||
|
||||
|
||||
int getch(void)
|
||||
{
|
||||
char ch;
|
||||
int error;
|
||||
static struct termios Otty, Ntty;
|
||||
|
||||
fflush(stdout);
|
||||
tcgetattr(0, &Otty);
|
||||
Ntty = Otty;
|
||||
|
||||
Ntty.c_iflag = 0; // input mode
|
||||
Ntty.c_oflag = 0; // output mode
|
||||
Ntty.c_lflag &= ~ICANON; // line settings
|
||||
Ntty.c_lflag &= ~ECHO; // enable echo
|
||||
Ntty.c_cc[VMIN] = CMIN; // minimum chars to wait for
|
||||
Ntty.c_cc[VTIME] = CTIME; // minimum wait time
|
||||
|
||||
// Conditionals allow compiling with or without flushing pre-existing
|
||||
// existing buffered input before blocking.
|
||||
#if 1
|
||||
// use this to flush the input buffer before blocking for new input
|
||||
# define FLAG TCSAFLUSH
|
||||
#else
|
||||
// use this to return a char from the current input buffer, or block if
|
||||
// no input is waiting.
|
||||
# define FLAG TCSANOW
|
||||
#endif
|
||||
|
||||
if (0 == (error = tcsetattr(0, FLAG, &Ntty)))
|
||||
{
|
||||
error = read(0, &ch, 1 ); // get char from stdin
|
||||
error += tcsetattr(0, FLAG, &Otty); // restore old settings
|
||||
}
|
||||
return (error == 1 ? (int) ch : -1 );
|
||||
}
|
||||
|
||||
|
||||
int getche(void)
|
||||
{
|
||||
char ch;
|
||||
int error;
|
||||
static struct termios Otty, Ntty;
|
||||
|
||||
fflush(stdout);
|
||||
tcgetattr(0, &Otty);
|
||||
Ntty = Otty;
|
||||
|
||||
Ntty.c_iflag = 0; // input mode
|
||||
Ntty.c_oflag = 0; // output mode
|
||||
Ntty.c_lflag &= ~ICANON; // line settings
|
||||
Ntty.c_lflag |= ECHO; // enable echo
|
||||
Ntty.c_cc[VMIN] = CMIN; // minimum chars to wait for
|
||||
Ntty.c_cc[VTIME] = CTIME; // minimum wait time
|
||||
|
||||
// Conditionals allow compiling with or without flushing pre-existing
|
||||
// existing buffered input before blocking.
|
||||
#if 1
|
||||
// use this to flush the input buffer before blocking for new input
|
||||
# define FLAG TCSAFLUSH
|
||||
#else
|
||||
// use this to return a char from the current input buffer, or block if
|
||||
// no input is waiting.
|
||||
# define FLAG TCSANOW
|
||||
#endif
|
||||
|
||||
if (0 == (error = tcsetattr(0, FLAG, &Ntty))) {
|
||||
error = read(0, &ch, 1 ); // get char from stdin
|
||||
error += tcsetattr(0, FLAG, &Otty); // restore old settings
|
||||
}
|
||||
|
||||
return (error == 1 ? (int) ch : -1 );
|
||||
}
|
||||
|
||||
} // namespace Tools
|
||||
} // namespace AS
|
||||
// ----------------------------------------------------------------------------
|
||||
#endif // System dependent parts
|
||||
// ============================================================================
|
||||
|
||||
//#define Test
|
||||
#if defined(Test)
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
char msg[] = "press key to continue...";
|
||||
char *ptr = msg, tmp;
|
||||
|
||||
while ( !OpenMesh::Utils::kbhit() )
|
||||
{
|
||||
tmp = *ptr;
|
||||
*ptr = islower(tmp) ? toupper(tmp) : tolower(tmp);
|
||||
printf("\r%s", msg); fflush(stdout);
|
||||
*ptr = (char)tmp;
|
||||
if (!*(++ptr))
|
||||
ptr = msg;
|
||||
usleep(20000);
|
||||
}
|
||||
|
||||
printf("\r%s.", msg); fflush(stdout);
|
||||
OpenMesh::Utils::getch();
|
||||
printf("\r%s..", msg); fflush(stdout);
|
||||
OpenMesh::Utils::getche();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // Test
|
||||
|
||||
// ============================================================================
|
||||
37
Tools/Utils/conio.hh
Normal file
37
Tools/Utils/conio.hh
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef OPENMESH_UTILS_CONIO_HH
|
||||
#define OPENMESH_UTILS_CONIO_HH
|
||||
// ----------------------------------------------------------------------------
|
||||
namespace OpenMesh {
|
||||
namespace Utils {
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/** Check if characters a pending in stdin.
|
||||
*
|
||||
* \return Number of characters available to read.
|
||||
*
|
||||
* \see getch(), getche()
|
||||
*/
|
||||
int kbhit(void);
|
||||
|
||||
|
||||
/** A blocking single character input from stdin
|
||||
*
|
||||
* \return Character, or -1 if an input error occurs.
|
||||
*
|
||||
* \see getche(), kbhit()
|
||||
*/
|
||||
int getch(void);
|
||||
|
||||
/** A blocking single character input from stdin with echo.
|
||||
*
|
||||
* \return Character, or -1 if an input error occurs.
|
||||
* \see getch(), kbhit()
|
||||
*/
|
||||
int getche(void);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
} // namespace Utils
|
||||
} // namespace OpenMesh
|
||||
// ----------------------------------------------------------------------------
|
||||
#endif // OPENMESH_UTILS_CONIO_HH
|
||||
// ============================================================================
|
||||
116
Tools/Utils/getopt.c
Normal file
116
Tools/Utils/getopt.c
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 1987, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "getopt.h"
|
||||
|
||||
int opterr = 1, /* if error message should be printed */
|
||||
optind = 1, /* index into parent argv vector */
|
||||
optopt, /* character checked for validity */
|
||||
optreset; /* reset getopt */
|
||||
char *optarg; /* argument associated with option */
|
||||
|
||||
#define BADCH (int)'?'
|
||||
#define BADARG (int)':'
|
||||
#define EMSG ""
|
||||
|
||||
/*
|
||||
* getopt --
|
||||
* Parse argc/argv argument vector.
|
||||
*/
|
||||
int
|
||||
getopt(int nargc, char * const *nargv, const char *ostr)
|
||||
{
|
||||
# define __progname nargv[0]
|
||||
static char *place = EMSG; /* option letter processing */
|
||||
char *oli; /* option letter list index */
|
||||
|
||||
if (optreset || !*place) { /* update scanning pointer */
|
||||
optreset = 0;
|
||||
if (optind >= nargc || *(place = nargv[optind]) != '-') {
|
||||
place = EMSG;
|
||||
return (-1);
|
||||
}
|
||||
if (place[1] && *++place == '-') { /* found "--" */
|
||||
++optind;
|
||||
place = EMSG;
|
||||
return (-1);
|
||||
}
|
||||
} /* option letter okay? */
|
||||
if ((optopt = (int)*place++) == (int)':' ||
|
||||
!(oli = strchr(ostr, optopt))) {
|
||||
/*
|
||||
* if the user didn't specify '-' as an option,
|
||||
* assume it means -1.
|
||||
*/
|
||||
if (optopt == (int)'-')
|
||||
return (-1);
|
||||
if (!*place)
|
||||
++optind;
|
||||
if (opterr && *ostr != ':')
|
||||
(void)fprintf(stderr,
|
||||
"%s: illegal option -- %c\n", __progname, optopt);
|
||||
return (BADCH);
|
||||
}
|
||||
if (*++oli != ':') { /* don't need argument */
|
||||
optarg = NULL;
|
||||
if (!*place)
|
||||
++optind;
|
||||
}
|
||||
else { /* need an argument */
|
||||
if (*place) /* no white space */
|
||||
optarg = place;
|
||||
else if (nargc <= ++optind) { /* no arg */
|
||||
place = EMSG;
|
||||
if (*ostr == ':')
|
||||
return (BADARG);
|
||||
if (opterr)
|
||||
(void)fprintf(stderr,
|
||||
"%s: option requires an argument -- %c\n",
|
||||
__progname, optopt);
|
||||
return (BADCH);
|
||||
}
|
||||
else /* white space */
|
||||
optarg = nargv[optind];
|
||||
place = EMSG;
|
||||
++optind;
|
||||
}
|
||||
return (optopt); /* dump back option letter */
|
||||
}
|
||||
|
||||
26
Tools/Utils/getopt.h
Normal file
26
Tools/Utils/getopt.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef _GETOPT_H_
|
||||
#define _GETOPT_H_
|
||||
|
||||
#include <OpenMesh/Core/System/compiler.hh>
|
||||
|
||||
#if defined(WIN32)
|
||||
#if defined(__cplusplus)
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern int opterr;
|
||||
extern int optind;
|
||||
extern int optopt;
|
||||
extern int optreset;
|
||||
extern char *optarg;
|
||||
|
||||
extern int getopt(int nargc, char * const *nargv, const char *ostr);
|
||||
|
||||
}
|
||||
|
||||
# endif
|
||||
#else
|
||||
# include <getopt.h>
|
||||
#endif
|
||||
|
||||
#endif /* _GETOPT_H_ */
|
||||
Reference in New Issue
Block a user