diff --git a/apps/pivoting/cmesh.h b/apps/pivoting/cmesh.h new file mode 100644 index 00000000..4671df96 --- /dev/null +++ b/apps/pivoting/cmesh.h @@ -0,0 +1,47 @@ +#ifndef CLOTH_MESH_H +#define CLOTH_MESH_H + +#include +#include +#include +#include +#include +#include + +#include + +using namespace vcg; + +class CVertex; +class CEdge; +class CFace; + +class CEdge { + public: + CVertex *v[2]; + CFace *f; + bool operator<(const CEdge& t) const { + if(v[0] < t.v[0]) return true; + if(v[0] > t.v[0]) return false; + return v[1] < t.v[1]; + } + bool operator==(const CEdge& t) const { + return v[0] == t.v[0] && v[1] == t.v[1]; + } +}; + +class CVertex: public + VertexSimp2 { + public: + float color; +}; + +class CFace: public FaceSimp2 {}; + +class CMesh: public tri::TriMesh< std::vector, std::vector > {}; + +#endif diff --git a/apps/pivoting/curvature.h b/apps/pivoting/curvature.h new file mode 100644 index 00000000..e69de29b diff --git a/apps/pivoting/glarea.cpp b/apps/pivoting/glarea.cpp new file mode 100644 index 00000000..99447c34 --- /dev/null +++ b/apps/pivoting/glarea.cpp @@ -0,0 +1,409 @@ + +#include +#include + +#include +#include +#include +#include +#include + +#include "glarea.h" +#include "cmesh.h" +#include +#include +#include +#include +#include + +#include +//#include "curvature.h" + + + + + +using namespace std; +using namespace vcg; + +GLArea::GLArea(QWidget *parent): QGLWidget(parent), pivot(NULL), smooth(false), radius(1.2) { + + tot = 1; + + setMouseTracking(true); +// init("uccello.ply", radius); +} + +bool GLArea::loadModel(const QString &file) { + + updateGL(); + return true; +} +void GLArea::open() { + QString file = QFileDialog::getOpenFileName(this, "Select a ply file", "", "*.ply"); + if(!file.size()) return; + init(file, radius); +} + +void GLArea::init(QString file, float ballsize = 1.2) { + + int err = tri::io::Importer::Open(mesh, file.toAscii().data()); + if(err) return; + mesh.face.clear(); + mesh.fn = 0; + +// UpdateTopology::VertexFace(mesh); +// UpdateTopology::FaceFace(mesh); +// tri::UpdateFlags::FaceBorderFromFF(mesh); +// tri::UpdateFlags::VertexBorderFromFace(mesh); + + //compute box; + box = Box3f(); + for(int i = 0; i < mesh.vert.size(); i++) + box.Add(mesh.vert[i].P()); + + + float r = sqrt((box.Diag()*box.Diag())/mesh.vn); + +// mesh.face.clear(); +// mesh.fn = 0; + if(pivot) delete pivot; + cout << "creating pibot\n"; + + NormalExtrapolation >::ExtrapolateNormals(mesh.vert.begin(), mesh.vert.end(), 10); +// pivot = new Pivot(mesh, r*ballsize, 0.1, 0); + pivot = new Pivot(mesh, 0, 0.1, 0); +// pivot.build(); +// pivot->buildMesh(); + +} + +void GLArea::save() { + + mesh.vn = mesh.vert.size(); + mesh.fn = mesh.face.size(); + tri::io::ExporterPLY::Save(mesh, "prova.ply"); + +} + +void GLArea::addFace() { + pivot->addFace(); + updateGL(); +/* std::list::iterator li; + for(li=pivot->front.begin();li!=pivot->front.end();++li) + printf("(%d-%d-%d)",(*li).v0,(*li).v1,(*li).v2); + printf("\n");*/ + +} + +void GLArea::add10Faces() { + for(int i =0; i < 10; i++) + if(-1 == pivot->addFace()) return; + + updateGL(); +} + + +void GLArea::add100Faces() { + for(int i =0; i < 100; i++) + if(-1 == pivot->addFace()) return; + updateGL(); +} + +void GLArea::add1000Faces() { + for(int i =0; i < 1000; i++) + if(-1 == pivot->addFace()) return; + updateGL(); +} + +void GLArea::addAll() { + while(1) { + for(int i = 0; i < 1000; i++) + if(0 > pivot->addFace()) return; + updateGL(); + } +} + +void GLArea::addTot() { + for(int i = 0; i < tot; i++) + if(0 > pivot->addFace()) return; + updateGL(); +} + + + +void GLArea::viewSmooth(bool on) { + smooth = on; + updateGL(); +} +void GLArea::initializeGL() { + glClearColor(1, 1, 1, 1); + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_COLOR_MATERIAL); + + glDisable(GL_BLEND); + glEnable(GL_NORMALIZE); + glDisable(GL_CULL_FACE); + glCullFace(GL_BACK); + glColor4f(1, 1, 1, 1); + + glEnable(GL_LIGHTING); + double st = 4; //1/sqrt(3); + float lpos[4]; + lpos[0] = lpos[1] = lpos[2] = st; + lpos[3] = 1; + glLightfv(GL_LIGHT0, GL_POSITION, lpos); + + float v[4] = {0.8, 0.8, 0.8, 0.0}; + glLightfv(GL_LIGHT0, GL_DIFFUSE, v); + + trackball.center=Point3f(0, 0, 0); + trackball.radius= 1; + + glLoadIdentity(); +} + + +void GLArea::resizeGL(int w, int h) { + glViewport(0, 0, (GLint)w, (GLint)h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + + float r = w/(float)h; + gluPerspective(60, r, 1, 4); + + glMatrixMode(GL_MODELVIEW); + +} + + +void GLArea::paintGL() { + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + glLoadIdentity(); + gluLookAt(0, 0, 3, 0, 0, 0, 0, 1, 0); + + //Drawing the scene + glPushMatrix(); + trackball.GetView(); + trackball.Apply(true); + + Point3f c = -box.Center(); + float radius = 2.0f/box.Diag(); + + if(mesh.face.size()>0) { + CFace &face = mesh.face[0]; + CVertex *v[3]; + v[0] = face.V(0); + c=-v[0]->P(); + radius=radius*5; + } + + if(!pivot) return; + + glPushMatrix(); + glScalef(radius, radius, radius); + glTranslatef(c[0], c[1], c[2]); + + if(pivot->front.size()>2) + { + glEnable(GL_LINE_SMOOTH); + glColor4f(1, 0, 1, 0.1); + glLineWidth(5); + Pivot::Edgex &ee=pivot->front.front(); + int v0=ee.v0; + int v1=ee.v1; + glBegin(GL_LINES); + glVertex3fv(mesh.vert[v0].P().V()); + glVertex3fv(mesh.vert[v1].P().V()); + glEnd(); + glLineWidth(1); + } + glEnable(GL_LIGHTING); + glColor3f(0, 1, 0); + + + + + + glBegin(GL_TRIANGLES); + for(int i = 0; i < mesh.face.size(); i++) { + CFace &face = mesh.face[i]; + CVertex *v[3]; + v[0] = face.V(0); + v[1] = face.V(1); + v[2] = face.V(2); + + Point3f n = (v[1]->P()- v[0]->P()) ^ (v[2]->P() - v[0]->P()); + //Point3f &n = face.N(); + glNormal3fv(&(n[0])); + + for(int k = 0; k < 3; k++) { + glVertex3fv((float *)&(v[k]->P())); + } + } + glEnd(); + + glEnable(GL_POLYGON_OFFSET_LINE); + glPolygonOffset(-3, -3); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + glDisable(GL_LIGHTING); + glColor3f(0, 0.5, 0); + + glPolygonOffset(-1, -1); + glBegin(GL_TRIANGLES); + for(int i = 0; i < mesh.face.size(); i++) { + CFace &face = mesh.face[i]; + CVertex *v[3]; + v[0] = face.V(0); + v[1] = face.V(1); + v[2] = face.V(2); + for(int k = 0; k < 3; k++) { + glVertex3fv((float *)&(v[k]->P())); + } + } + glEnd(); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + glDisable(GL_DEPTH_TEST); + glLineWidth(3.0f); + glBegin(GL_LINES); + for(list::Edgex>::iterator k = pivot->front.begin(); k != pivot->front.end(); k++) { + glColor3f(1, 0, 0); + Point3f &p0 = mesh.vert[(*k).v0].P(); + glVertex3fv(&(p0[0])); + glColor3f(0, 0, 1); + Point3f &p1 = mesh.vert[(*k).v1].P(); + glVertex3fv(&(p1[0])); + +/* glColor3f(1, 1, 0); + Point3f middle = (mesh.vert[(*k).v0].P() + mesh.vert[(*k).v1].P())/2; + glVertex3fv(&(middle[0])); + glVertex3fv(&((*k).center[0]));*/ + } + for(list::Edgex>::iterator k = pivot->deads.begin(); k != pivot->deads.end(); k++) { + glColor3f(0, 0, 0); + Point3f &p0 = mesh.vert[(*k).v0].P(); + glVertex3fv(&(p0[0])); + Point3f &p1 = mesh.vert[(*k).v1].P(); + glVertex3fv(&(p1[0])); + } + glEnd(); + glEnable(GL_DEPTH_TEST); + + glPointSize(4.0f); + glBegin(GL_POINTS); + for(int i = 0; i < mesh.vert.size(); i++) { + CVertex &v = mesh.vert[i]; + Point3f &p = v.P(); + if(v.IsD()) continue; + if(v.IsV()) glColor3f(1, 0, 0); + else if(v.IsB()) glColor3f(1, 1, 0); + else continue; + glVertex3f(p[0], p[1], p[2]); + } + glEnd(); + glColor3f(0, 0, 0); + glPointSize(1.0f); + + glLineWidth(1.0f); + glEnable(GL_LIGHTING); + + + glBegin(GL_LINES); + for(int i = 0; i < mesh.vert.size(); i++) { + CVertex &v = mesh.vert[i]; + Point3f &p = v.P(); + if(v.IsD()) continue; + glVertex3f(p[0], p[1], p[2]); + Point3f q = p + v.N(); + glVertex3f(q[0], q[1], q[2]); + } + glEnd(); + + + + + + glDisable(GL_POLYGON_OFFSET_LINE); + + + + + + glDisable(GL_LIGHTING); + glPopMatrix(); + + glScalef(radius, radius, radius); + glTranslatef(c[0], c[1], c[2]); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +// cloud.draw(); + glColor3f(0.5, 0.5, 0.5); + glPointSize(2); + glBegin(GL_POINTS); + for(int i = 0; i < mesh.vert.size(); i++) { + CVertex &vert = mesh.vert[i]; + Point3f n = vert.N(); + Point3f p = vert.P(); + glNormal3f(n[0], n[1], n[2]); + glVertex3f(p[0], p[1], p[2]); + } + glEnd(); + + glDisable(GL_BLEND); + glPopMatrix(); +} + +void GLArea::wheelEvent(QWheelEvent *e) { + if(e->delta() > 0) + trackball.MouseWheel(1); + else + trackball.MouseWheel(-1); + updateGL(); +} + +void GLArea::mouseMoveEvent(QMouseEvent *e) { + trackball.MouseMove(e->x(), height() - e->y()); + updateGL(); +} +Trackball::Button QT2VCG(Qt::MouseButton qtbt, Qt::KeyboardModifiers modifiers) +{ + int vcgbt=Trackball::BUTTON_NONE; + if(qtbt & Qt::LeftButton ) vcgbt |= Trackball::BUTTON_LEFT; + if(qtbt & Qt::RightButton ) vcgbt |= Trackball::BUTTON_RIGHT; + if(qtbt & Qt::MidButton ) vcgbt |= Trackball::BUTTON_MIDDLE; + if(modifiers & Qt::ShiftModifier ) vcgbt |= Trackball::KEY_SHIFT; + if(modifiers & Qt::ControlModifier ) vcgbt |= Trackball::KEY_CTRL; + if(modifiers & Qt::AltModifier ) vcgbt |= Trackball::KEY_ALT; + return Trackball::Button(vcgbt); +} + +void GLArea::keyReleaseEvent ( QKeyEvent * e ) +{ + if(e->key()==Qt::Key_Control) trackball.MouseUp(0,0, QT2VCG(Qt::NoButton, Qt::ControlModifier ) ); + if(e->key()==Qt::Key_Shift) trackball.MouseUp(0,0, QT2VCG(Qt::NoButton, Qt::ShiftModifier ) ); + if(e->key()==Qt::Key_Alt) trackball.MouseUp(0,0, QT2VCG(Qt::NoButton, Qt::AltModifier ) ); +} + +void GLArea::mousePressEvent(QMouseEvent *e) { + trackball.MouseDown(e->x(),height()-e->y(), QT2VCG(e->button(), e->modifiers() ) ); + // if(e->button() == Qt::LeftButton) + //trackball.MouseDown(e->x(), width() - e->y(), Trackball::BUTTON_LEFT); + // if(e->button() == Qt::RightButton) + // trackball.MouseDown(e->x(), width() - e->y(), Trackball::BUTTON_LEFT | Trackball::KEY_CTRL); +updateGL(); +} + +void GLArea::mouseReleaseEvent(QMouseEvent *e) { + trackball.MouseUp(e->x(),height()-e->y(), QT2VCG(e->button(), e->modifiers() ) ); + // if(e->button() == Qt::LeftButton) + //trackball.MouseUp(e->x(), width() - e->y(), Trackball::BUTTON_LEFT); + //if(e->button() == Qt::RightButton) + // trackball.MouseUp(e->x(), width() - e->y(), Trackball::BUTTON_LEFT | Trackball::KEY_CTRL); +} diff --git a/apps/pivoting/glarea.h b/apps/pivoting/glarea.h new file mode 100644 index 00000000..8c38e335 --- /dev/null +++ b/apps/pivoting/glarea.h @@ -0,0 +1,71 @@ +#ifndef CG_RENDERAREA_H +#define CG_RENDERAREA_H + +#include + +#include + +#include +#include +#include +#include "cmesh.h" + + +//#include "mls_surface.h" +//#include "advancing.h" + +using namespace tri; +using namespace trimesh; +class GLArea : public QGLWidget { + Q_OBJECT + +public: + + GLArea(QWidget *parent = 0); + bool smooth; + +public slots: + + bool loadModel(const QString &file); + void addFace(); + void add10Faces(); + void add100Faces(); + void add1000Faces(); + void addAll(); + void setTot(int n) { tot = n; } + void addTot(); + + void open(); + void save(); + void setRadius(double _radius) { + radius = _radius; + } + void viewSmooth(bool on); + +protected: + int tot; + + float radius; + vcg::Box3f box; + CMesh mesh; +// Pivot *pivot; + Pivot *pivot; + vcg::Trackball trackball; + + void init(QString file, float radius); + void draw(); + + + void initializeGL(); + void resizeGL(int w, int h); + void paintGL(); + + void wheelEvent(QWheelEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mousePressEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + void keyReleaseEvent ( QKeyEvent * e ); + +}; + +#endif diff --git a/apps/pivoting/main.cpp b/apps/pivoting/main.cpp new file mode 100644 index 00000000..1381b634 --- /dev/null +++ b/apps/pivoting/main.cpp @@ -0,0 +1,85 @@ +#include +using namespace std; + +#include +#include "mainwindow.h" + +class QMyWindow: public QMainWindow { + public: + QMyWindow(QWidget *parent): QMainWindow(parent) { + ui.setupUi(this); + if(!connect(ui.add_face, SIGNAL(clicked()), + ui.area, SLOT(addFace()))) { + cerr << "Could not connect addface\n"; + } + + if(!connect(ui.add_10_faces, SIGNAL(clicked()), + ui.area, SLOT(add10Faces()))) { + cerr << "Could not connect addface\n"; + } + + if(!connect(ui.add_100_faces, SIGNAL(clicked()), + ui.area, SLOT(add100Faces()))) { + cerr << "Could not connect addface\n"; + } + + if(!connect(ui.add_1000_faces, SIGNAL(clicked()), + ui.area, SLOT(add1000Faces()))) { + cerr << "Could not connect addface\n"; + } + if(!connect(ui.add_all, SIGNAL(clicked()), + ui.area, SLOT(addAll()))) { + cerr << "Could not connect addface\n"; + } + + if(!connect(ui.add, SIGNAL(clicked()), + ui.area, SLOT(addTot()))) { + cerr << "Could not connect addface\n"; + } + + + if(!connect(ui.save, SIGNAL(clicked()), + ui.area, SLOT(save()))) { + cerr << "Could not connect addface\n"; + } + if(!connect(ui.smooth, SIGNAL(clicked(bool)), + ui.area, SLOT(viewSmooth(bool)))) { + cerr << "Could not connect addface\n"; + } + if(!connect(ui.open, SIGNAL(clicked()), + ui.area, SLOT(open()))) { + cerr << "Could not connect addface\n"; + } + if(!connect(ui.radius, SIGNAL(valueChanged(double)), + ui.area, SLOT(setRadius(double)))) { + cerr << "Could not connect addface\n"; + } + if(!connect(ui.tot, SIGNAL(valueChanged(int)), + ui.area, SLOT(setTot(int)))) { + cerr << "Could not connect addface\n"; + } + + + /* connect(ui.world, SIGNAL(activated(const QString&)), + ui.area, SLOT(loadWorld(const QString&))); + + connect(ui.shadow, SIGNAL(activated(int)), + ui.area, SLOT(setShadowMode(int))); + + connect(ui.drawvolume, SIGNAL(clicked(bool)), + ui.area, SLOT(setDrawVolume(bool))); + + connect(ui.track, SIGNAL(activated(int)), + ui.area, SLOT(setTrackMode(int)));*/ + } + private: + Ui::MainWindow ui; +}; + +int main(int argc, char *argv[]) { + QApplication app(argc, argv); + QMyWindow *window = new QMyWindow(NULL); + + window->show(); + return app.exec(); +} diff --git a/apps/pivoting/mainwindow.ui b/apps/pivoting/mainwindow.ui new file mode 100644 index 00000000..33785ca9 --- /dev/null +++ b/apps/pivoting/mainwindow.ui @@ -0,0 +1,465 @@ + + + + + MainWindow + + + + 0 + 0 + 717 + 727 + + + + + + + 128 + 128 + 128 + + + 255 + 255 + 255 + + + 255 + 255 + 255 + + + 255 + 255 + 255 + + + 127 + 127 + 127 + + + 170 + 170 + 170 + + + 128 + 128 + 128 + + + 255 + 255 + 255 + + + 128 + 128 + 128 + + + 255 + 255 + 255 + + + 255 + 255 + 255 + + + 0 + 0 + 0 + + + 49 + 106 + 197 + + + 255 + 255 + 255 + + + 0 + 0 + 255 + + + 255 + 0 + 255 + + + 255 + 255 + 255 + + + + + 128 + 128 + 128 + + + 255 + 255 + 255 + + + 255 + 255 + 255 + + + 255 + 255 + 255 + + + 127 + 127 + 127 + + + 170 + 170 + 170 + + + 128 + 128 + 128 + + + 255 + 255 + 255 + + + 128 + 128 + 128 + + + 255 + 255 + 255 + + + 255 + 255 + 255 + + + 0 + 0 + 0 + + + 49 + 106 + 197 + + + 255 + 255 + 255 + + + 0 + 0 + 255 + + + 255 + 0 + 255 + + + 255 + 255 + 255 + + + + + 128 + 128 + 128 + + + 255 + 255 + 255 + + + 255 + 255 + 255 + + + 255 + 255 + 255 + + + 127 + 127 + 127 + + + 170 + 170 + 170 + + + 128 + 128 + 128 + + + 255 + 255 + 255 + + + 128 + 128 + 128 + + + 255 + 255 + 255 + + + 255 + 255 + 255 + + + 0 + 0 + 0 + + + 49 + 106 + 197 + + + 255 + 255 + 255 + + + 0 + 0 + 255 + + + 255 + 0 + 255 + + + 255 + 255 + 255 + + + + + + MainWindow + + + + + 9 + + + 6 + + + + + + 1 + 1 + 0 + 0 + + + + + 120 + 70 + + + + + 120 + 300 + + + + + + + + 9 + + + 6 + + + + + 10000000 + + + 1 + + + + + + + Add + + + + + + + Add 1 face + + + + + + + Add 100 faces + + + + + + + Add 10 faces + + + + + + + Open... + + + + + + + smooth + + + + + + + 10 + + + 0.5 + + + 0.1 + + + 1.2 + + + + + + + Save + + + + + + + <html><head><meta name="qrichtext" content="1" /></head><body style=" white-space: pre-wrap; font-family:MS Shell Dlg; font-size:8.25pt; font-weight:400; font-style:normal; text-decoration:none;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">R:</span></p></body></html> + + + + + + + Add 1000 faces + + + + + + + Add all + + + + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 20 + 271 + + + + + + + + + 7 + 7 + 0 + 0 + + + + + + + + + + + GLArea + QFrame +
glarea.h
+ 0 + +
+
+ + +
diff --git a/apps/pivoting/pivot.dev b/apps/pivoting/pivot.dev new file mode 100644 index 00000000..fb7e306e --- /dev/null +++ b/apps/pivoting/pivot.dev @@ -0,0 +1,242 @@ +[Project] +FileName=pivot.dev +Name=pivot +UnitCount=8 +Type=1 +Ver=1 +ObjFiles= +Includes= +Libs= +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler= +CppCompiler=-I ../../../sf_@@_-I ../../../code/lib/ANNf/include_@@_ +Linker=-lQtCore4_@@_-lQtGui4_@@_-lQtOpenGL4_@@_-lopengl32_@@_-lglu32_@@_-implib ../../../code/lib/glew/lib/glew32.dll _@@_../../../code/lib/ANNf/lib/libANN.a_@@__@@__@@_ +IsCpp=1 +Icon= +ExeOutput= +ObjectOutput= +OverrideOutput=0 +OverrideOutputName=transform.exe +HostApplication= +Folders= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000001001001001000100 + +[Unit1] +FileName=glarea.h +CompileCpp=1 +Folder=transform +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=main.cpp +CompileCpp=1 +Folder=transform +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit3] +FileName=glarea.cpp +CompileCpp=1 +Folder= +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Developed using the Dev-C++ IDE +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + +[Unit4] +FileName=cmesh.h +CompileCpp=1 +Folder=farsa +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit5] +FileName=..\..\wrap\gui\trackmode.cpp +CompileCpp=1 +Folder=pivot +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit6] +FileName=..\..\wrap\gui\trackball.cpp +CompileCpp=1 +Folder=pivot +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit14] +FileName=cmesh.h +CompileCpp=1 +Folder=farsa +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit16] +FileName=space_hash.cpp +CompileCpp=1 +Folder= +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit18] +FileName=matrix.cpp +CompileCpp=1 +Folder=farsa +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit19] +FileName=eigen.h +CompileCpp=1 +Folder=farsa +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit20] +FileName=leigen.h +CompileCpp=1 +Folder=farsa +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit21] +FileName=q_surface.cpp +CompileCpp=1 +Folder= +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit15] +FileName=space_hash.h +CompileCpp=1 +Folder= +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit13] +FileName=curvature.h +CompileCpp=1 +Folder=farsa +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit17] +FileName=pivot.h + +[Unit8] +FileName=moc_glarea.cpp +CompileCpp=1 +Folder=pivot +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit11] +FileName=pivot.h +CompileCpp=1 +Folder= +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit7] +FileName=..\..\wrap\ply\plylib.cpp +CompileCpp=1 +Folder=pivot +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit9] +FileName=..\..\sf\vcg\space\normal_extrapolation.h +CompileCpp=1 +Folder=pivot +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit10] +FileName=..\..\sf\vcg\complex\trimesh\create\ball_pivoting.h +CompileCpp=1 +Folder=pivot +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + diff --git a/apps/pivoting/pivot.h b/apps/pivoting/pivot.h new file mode 100644 index 00000000..1964a685 --- /dev/null +++ b/apps/pivoting/pivot.h @@ -0,0 +1,753 @@ +#ifndef VCG_PIVOT_H +#define VCG_PIVOT_H + +#include +#include + + +#include "vcg/space/index/grid_static_ptr.h" +#include "vcg/complex/trimesh/closest.h" + +namespace vcg { +namespace tri { + + +struct Hinge { + int v0, v1, v2; //v0, v1 represent the Hinge, v2 the other vertex in the face + //this Hinge belongs to + int face; //corresponding face + Point3f center; //center of the sphere touching the face + int count; //test delay touch Hinges. + + //the loops in the front are mantained as a double linked list + std::list::iterator next; + std::list::iterator previous; + + Hinge() {} + Hinge(int _v0, int _v1, int _v2, int _face, Point3f &_center): + v0(_v0), v1(_v1), v2(_v2), + face(_face), center(_center), count(0) { + assert(v0 != v1 && v1 != v2 && v0 != v2); + } + }; + +template +class Pivot { + public: +// typedef CMesh MESH; + typedef GridStaticPtr StaticGrid; + + + + float radius; //default 1 (not meaningful + float mindist; //minimum distance between points in the mesh (% of radius) + float crease; // -0.5 + Box3f box; + + MESH &mesh; + StaticGrid grid; + + /* front Hinges of the mesh: + to expand the front we get the first Hinge + if an Hinge cannot create a new triangle it is marked dead and moved + to the end of the list + the new Hinges are inserted to the back (before dead_begin) */ + + std::list front; + std::list deads; + std::vector nb; //number of fronts a vertex is into, + //this is used for the Visited and Border flags + //but adding topology may not be needed anymode + + + Pivot(MESH &_mesh, float _radius, float _mindist = 0.05, float _crease = -0.5): + mesh(_mesh), radius(_radius), mindist(_mindist), crease(_crease) { + + //Compute bounding box. (this may be passed as a parameter? + for(int i = 0; i < mesh.vert.size(); i++) + box.Add(mesh.vert[i].P()); + + /* we need to enlarge the grid to allow queries from little outside of the box + Someone is a bit lazy... */ + box.Offset(4*radius); + grid.Set(mesh.vert.begin(), mesh.vert.end(), box); + nb.clear(); + nb.resize(mesh.vert.size(), 0); + for(int i = 0; i < mesh.vert.size(); i++) + mesh.vert[i].ClearFlags(); + + } + + + /* select a vertex at random, a small group of nearby vertices and looks + for a sphere that touches 3 and contains none. + Use the center of the box to get a sphere inside (or outside) the model + You may be unlucky... */ + + bool seed(bool outside = true, int start = -1) { + //pick a random point (well...) + if(start == -1) start = rand()%mesh.vert.size(); + + //get a sphere of neighbours + std::vector targets; + std::vector dists; + int n = getInSphere(mesh.vert[start].P(), 2*radius, targets, dists); + if(n < 3) { + //bad luck. we should call seed again (assuming random pick) up to + //some maximum tries. im lazy. + return false; + } + int v0, v1, v2; + bool found = false; + //find a triplet that does not contains any other point + Point3f center; + for(int i = 0; i < n; i++) { + v0 = targets[i]; + CVertex &vv0 = mesh.vert[v0]; + if(vv0.IsD() || vv0.IsB() || vv0.IsV()) continue; + Point3f &p0 = mesh.vert[v0].P(); + Point3f out = (p0 - box.Center()); + if(!outside) out = -out; + + for(int k = i+1; k < n; k++) { + v1 = targets[k]; + CVertex &vv1 = mesh.vert[v1]; + if(vv1.IsD() || vv1.IsB() || vv1.IsV()) continue; + Point3f &p1 = mesh.vert[v1].P(); + if((p1 - p0).Norm() < mindist*radius) continue; + + for(int j = k+1; j < n; j++) { + v2 = targets[j]; + CVertex &vv2 = mesh.vert[v2]; + if(vv2.IsD() || vv2.IsB() || vv2.IsV()) continue; + Point3f &p2 = mesh.vert[v2].P(); + if((p2 - p0).Norm() < mindist*radius) continue; + if((p2 - p1).Norm() < mindist*radius) continue; + Point3f normal = (p1 - p0)^(p2 - p0); + //check normal pointing inside + if(normal * out < 0) continue; + if(!findSphere(p0, p1, p2, center)) continue; + + bool failed = false; + //check no other point inside + for(int t = 0; t < n; t++) { + Point3f &p = mesh.vert[targets[t]].P(); + if((center - p).Norm() <= radius) { + failed = true; + break; + } + } + if(failed) continue; + found = true; + i = k = j = n; + } + } + } + + if(!found) //see bad luck above + return false; + + assert(!front.size()); + //TODO: should i check the Hinges too? + addFace(v0, v1, v2); + + //create the border of the first face + std::list::iterator e = front.end(); + std::list::iterator last; + for(int i = 0; i < 3; i++) { + int v0 = (int)(mesh.face.back().V0(i)); + int v1 = (int)(mesh.face.back().V1(i)); + int v2 = (int)(mesh.face.back().V2(i)); + nb[v0] = 1; + assert(!mesh.vert[v0].IsB()); + mesh.vert[v0].SetB(); + Hinge Hinge(v0, v1, v2, 0, center); + Hinge.previous = e; + e = front.insert(front.begin(), Hinge); + if(i == 0) last = e; + (*Hinge.previous).next = e; + + cluster(v0); + } + + //connect last and first + (*e).next = last; + (*last).previous = e; + return true; + } + + + /* expand the front adding 1 face. Return false on failure (id when + all Hinges are dead returns: + 1: added a face + 0: added nothing + -1: finished */ + int addFace() { + //We try to seed again + if(!mesh.face.size()) { + for(int i = 0; i < 100; i++) + if(seed()) return 1; + return -1; + } + + if(!front.size()) { + //maybe there are unconnected parts of the mesh: + //find a non D, V, B point and try to seed if failed D it. + for(int i = 0; i < mesh.vert.size();i ++) { + CVertex &v = mesh.vert[i]; + if(v.IsD() || v.IsV() || v.IsB()) continue; + if(seed(true, i)) return 1; + v.SetD(); + } + return -1; + } + + std::list::iterator ei = front.begin(); + Hinge &e = *ei; + Hinge &previous = *e.previous; + Hinge &next = *e.next; + int v0 = e.v0, v1 = e.v1; + + //last triangle missing. or it is the first? + if(0 &&next.next == e.previous) { + + int v[3] = { previous.v0, next.v0, e.v0 }; + int c[3] = { 0, 0, 0 }; + + for(int k = 0; k < 3; k++) { + int vert = v[k]; + nb[vert]--; + if(nb[vert] == 0) { + mesh.vert[vert].SetV(); + mesh.vert[vert].ClearB(); + } + } + assert(previous.previous == e.next); + addFace(previous.v0, next.v0, e.v0); + + front.erase(e.previous); + front.erase(e.next); + front.erase(ei); + + return 1; + } + + int v2; + Point3f center; + + std::vector targets; + bool success = pivot(e, v2, center, targets); + + //if no pivoting move this thing to the end and try again + //or we are trying to connect to the inside of the mesh. BAD. + if(!success || mesh.vert[v2].IsV()) { + killHinge(ei); + return 0; + } + + //does v2 belongs to a front? (and which?) + std::list::iterator touch = touches(v2, ei); + + assert(v2 != v0 && v2 != v1); + + int fn = mesh.face.size(); + if(touch != front.end()) { + + if(!checkHinge(v0, v2) || !checkHinge(v2, v1)) { + killHinge(ei); + return 0; + } + + if(v2 == previous.v0) { + /*touching previous Hinge (we reuse previous) + next + ------->v2 -----> v1------> + \ / + \ / + previous \ / e + \ / + v0 */ + + detach(v0); + + previous.v1 = v1; + previous.v2 = v0; + previous.face = fn; + previous.center = center; + + previous.next = e.next; + next.previous = e.previous; + moveBack(e.previous); + + //this checks if we can glue something to e.previous + trovamiunnome(e.previous); + front.erase(ei); + + + } else if(v2 == next.v1) { + /*touching previous Hinge (we reuse next) + previous + ------->v0 -----> v2------> + \ / + \ / + \ / next + \ / + v1 */ + + detach(v1); + + next.v0 = v0; + next.v2 = v1; + next.face = fn; + next.center = center; + next.previous = e.previous; + previous.next = e.next; + // moveBack(e.next); + + //this checks if we can glue something to e.previous + trovamiunnome(e.next); + front.erase(ei); + + } else { + + /* this code would delay the joining Hinge to avoid bad situations not used but.. + if(e.count < 2) { + e.count++; + moveBack(ei); + return true; + }*/ + + //touching some loop: split (or merge it is local does not matter. + //like this + /* + left right + <--------v2-<------ + /|\ + / \ + up / \ down + / \ + / V + ----v0 - - - > v1--------- + e */ + std::list::iterator left = touch; + std::list::iterator right = (*touch).previous; + std::list::iterator up = ei; + + if(v1 == (*right).v0 || v0 == (*left).v1) { +// cout << "Bad join.\n"; + killHinge(ei); + return 0; + } + + nb[v2]++; + + std::list::iterator down = newHinge(Hinge(v2, v1, v0, fn, center)); + + (*right).next = down; + (*down).previous = right; + + (*down).next = e.next; + next.previous = down; + + (*left).previous = up; + (*up).next = left; + + (*up).v2 = v1; + (*up).v1 = v2; + (*up).face = fn; + (*up).center = center; + moveBack(ei); + } + + + + } else { + assert(!mesh.vert[v2].IsB()); //fatal error! a new point is already a border? + + /* adding a new vertex + + v2 + /|\ + / \ + up / \ down + / \ + / V + ----v0 - - - > v1--------- */ + cluster(v2); + nb[v2]++; + mesh.vert[v2].SetB(); + std::list::iterator down = newHinge(Hinge(v2, v1, v0, fn, center)); + (*down).previous = ei; + (*down).next = e.next; + next.previous = down; + + e.v2 = v1; + e.v1 = v2; + e.face = fn; + e.center = center; + e.next = down; + moveBack(ei); + } + addFace(v0, v2, v1); + return 1; + } + + + + /* return new vertex and the center of the new sphere pivoting from Hinge + if the vertex belongs to another Hinge, touch points to it. */ + bool pivot(Hinge &Hinge, int &candidate, Point3f &end_pivot, std::vector &targets) { + Point3f v0 = mesh.vert[Hinge.v0].P(); + Point3f v1 = mesh.vert[Hinge.v1].P(); + Point3f v2 = mesh.vert[Hinge.v2].P(); + /* TODO why using the face normals everything goes wrong? should be + exactly the same................................................ + Check if the e.face is correct. + Point3f &normal = mesh.face[Hinge.face].N(); + */ + + Point3f normal = ((v1 - v0)^(v2 - v0)).Normalize(); + + Point3f middle = (v0 + v1)/2; + Point3f start_pivot = Hinge.center - middle; + Point3f axis = (v1 - v0); + + float axis_len = axis.SquaredNorm(); + if(axis_len > 4*radius*radius) return false; + axis.Normalize(); + + // r is the radius of the thorus of all possible spheres passing throug v0 and v1 + float r = sqrt(radius*radius - axis_len/4); + + + std::vector dists; + getInSphere(middle, r + radius, targets, dists); + + if(targets.size() == 0) return false; //this really would be strange but one never knows. + + candidate = -1; + float minangle = 0; + Point3f center; //to be computed for each sample + for(int i = 0; i < targets.size(); i++) { + int id = targets[i]; + + if(id == Hinge.v0 || id == Hinge.v1 || id == Hinge.v2) continue; + + if(mesh.vert[id].IsD()) { + continue; + } + + + Point3f p = mesh.vert[id].P(); + + /* Prevent 360 Hinges, also often reject ~ 50% points */ + Point3f n = ((p - v0)^(v1 - v0)).Normalize(); + if(n * normal < -0.5) { + continue; + } + + + /* Find the sphere through v0, p, v1 (store center on end_pivot */ + if(!findSphere(v0, p, v1, center)) { + continue; + } + + /* Angle between old center and new center */ + float alpha = angle(start_pivot, center - middle, axis); + + /* adding a small bias to already chosen vertices. + doesn't solve numerical problems, but helps. */ + if(mesh.vert[id].IsB()) alpha -= 0.001; + + /* Sometimes alpha might be little less then M_PI while it should be 0, + by numerical errors: happens for example pivoting + on the diagonal of a square. */ + + if(alpha > 2*M_PI - 0.8) { + // Angle between old center and new *point* + //TODO is this really overshooting? shouldbe enough to alpha -= 2*M_PI + Point3f proj = p - axis * (axis * p - axis * middle); + float beta = angle(start_pivot, proj - middle, axis); + + if(alpha > beta) alpha -= 2*M_PI; + } + if(candidate == -1 || alpha < minangle) { + candidate = id; + minangle = alpha; + end_pivot = center; + } + } + //found no point suitable. + if(candidate == -1) { + return false; + } + + assert(candidate != Hinge.v0 && candidate != Hinge.v1); + return true; + } + + private: + //front management: + //Add a new Hinge to the back of the queue + std::list::iterator newHinge(Hinge e) { + return front.insert(front.end(), e); + } + //move an Hinge among the dead ones + void killHinge(std::list::iterator e) { + deads.splice(deads.end(), front, e); + } + + //move an Hinge to the back of the queue + void moveBack(std::list::iterator e) { + front.splice(front.end(), front, e); + } + + void moveFront(std::list::iterator e) { + front.splice(front.begin(), front, e); + } + bool checkHinge(int v0, int v1) { + int tot = 0; + //HACK to speed up things until i can use a seach structure + int i = mesh.face.size() - 2*(front.size()); + // i = 0; + if(i < 0) i = 0; + for(; i < mesh.face.size(); i++) { + CFace &f = mesh.face[i]; + for(int k = 0; k < 3; k++) { + if(v1== (int)f.V(k) && v0 == (int)f.V((k+1)%3)) ++tot; + else if(v0 == (int)f.V(k) && v1 == (int)f.V((k+1)%3)) { //orientation non constistent + return false; + } + } + if(tot >= 2) { //non manifold + return false; + } + } + return true; + } + + + void Pivot::cluster(int v) { + /* clean up too close points */ + std::vector targets; + std::vector dists; + getInSphere(mesh.vert[v].P(), mindist*radius, targets, dists); + + for(int i = 0; i < targets.size(); i++) { + int id = targets[i]; + if(id == v) continue; + + CVertex &v = mesh.vert[id]; + if(v.IsD() || v.IsV() || v.IsB()) continue; + v.SetD(); + } + + } + + void Pivot::trovamiunnome(std::list::iterator e) { + if(glue((*e).previous, e)) return; + glue(e, (*e).next); + } + + //glue toghether a and b (where a.next = b + bool Pivot::glue(std::list::iterator a, std::list::iterator b) { + if((*a).v0 != (*b).v1) return false; + + std::list::iterator previous = (*a).previous; + std::list::iterator next = (*b).next; + (*previous).next = next; + (*next).previous = previous; + detach((*a).v1); + detach((*a).v0); + front.erase(a); + front.erase(b); + return true; + } + + void Pivot::detach(int v) { + assert(nb[v] > 0); + if(--nb[v] == 0) { + mesh.vert[v].SetV(); + mesh.vert[v].ClearB(); + } + } + + + /* compute angle from p to q, using axis for orientation */ + float angle(Point3f p, Point3f q, Point3f &axis) { + p.Normalize(); + q.Normalize(); + Point3f vec = p^q; + float angle = acos(p*q); + if(vec*axis < 0) angle = -angle; + if(angle < 0) angle += 2*M_PI; + return angle; + } + /* add a new face. compute normals. */ + void addFace(int a, int b, int c) { + CFace face; + face.V(0) = (CVertex *)a; + face.V(1) = (CVertex *)b; + face.V(2) = (CVertex *)c; + Point3f &p0 = mesh.vert[a].P(); + Point3f &p1 = mesh.vert[b].P(); + Point3f &p2 = mesh.vert[c].P(); + face.N() = ((p1 - p0)^(p2 - p0)).Normalize(); + + mesh.face.push_back(face); + mesh.fn++; + } + + + /* intersects segment [v0, v1] with the sphere of radius radius. */ + bool intersect(int v0, int v1, Point3f ¢er) { + Point3f m = mesh.vert[v1].P() - mesh.vert[v0].P(); + float t = m*(center - mesh.vert[v0].P()); + if(t < 0) return false; + if(t > m*m) return false; + return true; + } + + + float distance(int v0, int v1, Point3f ¢er) { + Point3f m = mesh.vert[v1].P() - mesh.vert[v0].P(); + float t = m*(center - mesh.vert[v0].P())/(m*m); + Point3f p = mesh.vert[v0].P() + m*t; + return (p - center).Norm(); + } + + + /* return all point in a given ball, notice as i want the index + of the vertices not the pointers... this may change in future */ + unsigned int getInSphere(vcg::Point3f &p, float distance, + std::vector &results, + std::vector &dists) { + std::vector ptr; + std::vector points; + int n = vcg::trimesh::GetInSphereVertex(mesh, grid, p, distance, ptr, dists, points); + for(int i = 0; i < ptr.size(); i++) + results.push_back(ptr[i] - &(mesh.vert[0])); + return n; + } + + + + /* returns the sphere touching p0, p1, p2 of radius r such that + the normal of the face points toward the center of the sphere */ + bool findSphere(Point3f &p0, Point3f &p1, Point3f &p2, Point3f ¢er) { + Point3f q1 = p1 - p0; + Point3f q2 = p2 - p0; + + Point3f up = q1^q2; + float uplen = up.Norm(); + + //the three points are aligned + if(uplen < 0.001*q1.Norm()*q2.Norm()) return false; + up /= uplen; + + + float a11 = q1*q1; + float a12 = q1*q2; + float a22 = q2*q2; + + float m = 4*(a11*a22 - a12*a12); + float l1 = 2*(a11*a22 - a22*a12)/m; + float l2 = 2*(a11*a22 - a12*a11)/m; + + center = q1*l1 + q2*l2; + float circle_r = center.Norm(); + if(circle_r > radius) return false; //need too big a sphere + + float height = sqrt(radius*radius - circle_r*circle_r); + center += p0 + up*height; + + return true; + } + std::list::iterator touches(int v, std::list::iterator e) { + //TODO what happens when it touches more than one front? + //might still work. + + std::list::iterator touch = front.end(); + if(mesh.vert[v].IsB()) { + //test nearby Hinges: it is faster + std::list::iterator p = e; + p = (*e).previous; + if(v == (*p).v0) return p; + e = (*e).next; + if(v == (*e).v0) return e; + + p = (*p).previous; + if(v == (*p).v0) return p; + e = (*e).next; + if(v == (*e).v0) return e; + + //test all. sigh. + + for(std::list::iterator k = front.begin(); k != front.end(); k++) { + if(v == (*k).v0) { + touch = k; + break; + } + } + for(std::list::iterator k = deads.begin(); k != deads.end(); k++) { + if(v == (*k).v0) { + touch = k; + break; + } + } + assert(touch != front.end()); + } + + return touch; + } + + + public: + + }; + + +}//namespace +}//namespace +/* CODE FOR PIVOTING IN A TOUCH SITUATION not used now. + + //if touch we want to check the ball could really pivot around that point + if(touch != front.end() && touch != (*Hinge.next).next && touch != Hinge.previous) { + Point3f &hinge = mesh.vert[min].P(); + Point3f target = (*touch).center - hinge; + float d = (target * start_pivot)/(target.Norm()*start_pivot.Norm()); + if(d < -0.8) { + return false; + } + + + + if(d < 0.5) { //they are far enough so test . + Point3f naxis = (target ^ start_pivot).Normalize(); + Point3f d1 = naxis^start_pivot; + Point3f d2 = target^naxis; + + for(int i = 0; i < targets.size(); i++) { + int id = targets[i]; + if(id == Hinge.v0 || id == Hinge.v1 || id == Hinge.v2 || id == min) continue; + if(mesh.vert[id].IsD()) { + continue; + } + + Point3f intruder = mesh.vert[targets[i]].P() - hinge; + float h = intruder*naxis; + if(fabs(h) > radius) continue; + intruder -= naxis*h; + assert(fabs(intruder *naxis) < 0.01); + float off = radius - intruder.Norm(); //(distance from the center ring of the thorus + if(h*h + off*off > radius*radius) continue; //outside of thorus + if(d1*intruder < 0 || d2*intruder < 0) continue; //ouside of sector + cout << "could not pivot while touching;\n"; + return false; + } + + } + }*/ + + +#endif diff --git a/apps/pivoting/ring.h b/apps/pivoting/ring.h new file mode 100644 index 00000000..e9f08de8 --- /dev/null +++ b/apps/pivoting/ring.h @@ -0,0 +1,129 @@ +#ifndef RING_H +#define RING_H +// Making a "ring" data structure from the STL +#include +using namespace std; + +template +class ring { + list lst; +public: + + ring &operator=(const ring *r) { + lst = r->lst; + } + // Declaration necessary so the following + // 'friend' statement sees this 'iterator' + // instead of std::iterator: + class iterator; + friend class iterator; + class iterator : + public std::iterator { + + public: + typename list::iterator it; + list* r; + + + // "typename" necessary to resolve nesting: + + iterator(): r(NULL) {} + iterator(list& lst, const typename list::iterator& i) + : r(&lst), it(i) {} + + iterator &operator=(const iterator& x) { + it = x.it; + r = x.r; + return *this; + } + + bool operator==(const iterator& x) const { + return it == x.it; + } + + bool operator!=(const iterator& x) const { + return !(*this == x); + } + + typename list::reference operator*() const { + return *it; + } + + iterator& operator++() { + ++it; + if(it == r->end()) + it = r->begin(); + return *this; + } + + iterator operator++(int) { + iterator tmp = *this; + ++*this; + return tmp; + } + + iterator& operator--() { + if(it == r->begin()) + it = r->end(); + --it; + return *this; + } + + iterator operator--(int) { + iterator tmp = *this; + --*this; + return tmp; + } + + iterator operator+(int i) { + iterator tmp = *this; + while(i--) ++tmp; + return tmp; + } + + iterator operator-(int i) { + iterator tmp = *this; + while(i--) --tmp; + return tmp; + } + + iterator insert(const T& x){ + return iterator(*r, r->insert(it, x)); + } + + iterator erase() { + iterator tmp = iterator(*r, r->erase(it)); + + if (tmp.it == r->end()) tmp.it = r->begin(); + + return tmp; + } + }; + + iterator insert(iterator &i, const T& x) { + typename list::iterator it; + it = lst.insert(i.it, x); + return iterator(lst, it); + } + + iterator push_back(const T& x) { + typename list::iterator it; + it = lst.insert(lst.end(), x); + return iterator(lst, it); + + } + /* void push_back(const T& x) { + lst.push_back(x); + }*/ + + iterator begin() { + return iterator(lst, lst.begin()); + } + + int size() { return lst.size(); } + void clear() { lst.clear(); } + void reverse() { lst.reverse(); } + void erase(iterator &i) { lst.erase(i.it); } +}; + +#endif