This commit is contained in:
Federico Ponchio 2007-05-10 08:36:46 +00:00
parent 1f61ffc1ca
commit f01483d94f
9 changed files with 2201 additions and 0 deletions

47
apps/pivoting/cmesh.h Normal file
View File

@ -0,0 +1,47 @@
#ifndef CLOTH_MESH_H
#define CLOTH_MESH_H
#include <vcg/simplex/vertexplus/base.h>
#include <vcg/simplex/faceplus/base.h>
#include <vcg/simplex/face/pos.h>
#include <vcg/simplex/face/topology.h>
#include <vcg/complex/trimesh/base.h>
#include <vcg/complex/trimesh/update/normal.h>
#include <vector>
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<CVertex, CEdge, CFace,
vcg::vert::Coord3f, vert::Normal3f, vert::BitFlags, vert::Mark,
vert::VFAdj,
vert::Qualityf> {
public:
float color;
};
class CFace: public FaceSimp2 <CVertex, CEdge, CFace, face::VertexRef,
face::BitFlags, face::VFAdj, face::FFAdj > {};
class CMesh: public tri::TriMesh< std::vector<CVertex>, std::vector<CFace> > {};
#endif

View File

409
apps/pivoting/glarea.cpp Normal file
View File

@ -0,0 +1,409 @@
#include <math.h>
#include <iostream>
#include <QtCore/QFile>
#include <QtGui/QMouseEvent>
#include <QtGui/QMessageBox>
#include <QtGui/QImage>
#include <QtGui/QFileDialog>
#include "glarea.h"
#include "cmesh.h"
#include <wrap/io_trimesh/import.h>
#include <wrap/io_trimesh/export.h>
#include <vcg/complex/trimesh/update/normal.h>
#include <vcg/complex/trimesh/update/topology.h>
#include <vcg/complex/trimesh/update/flag.h>
#include <vcg/space/normal_extrapolation.h>
//#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<CMesh>::Open(mesh, file.toAscii().data());
if(err) return;
mesh.face.clear();
mesh.fn = 0;
// UpdateTopology<CMesh>::VertexFace(mesh);
// UpdateTopology<CMesh>::FaceFace(mesh);
// tri::UpdateFlags<CMesh>::FaceBorderFromFF(mesh);
// tri::UpdateFlags<CMesh>::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<vector<CVertex> >::ExtrapolateNormals(mesh.vert.begin(), mesh.vert.end(), 10);
// pivot = new Pivot<CMesh>(mesh, r*ballsize, 0.1, 0);
pivot = new Pivot<CMesh>(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<CMesh>::Save(mesh, "prova.ply");
}
void GLArea::addFace() {
pivot->addFace();
updateGL();
/* std::list<Hinge>::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<CMesh>::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<Pivot<CMesh>::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<Pivot<CMesh>::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);
}

71
apps/pivoting/glarea.h Normal file
View File

@ -0,0 +1,71 @@
#ifndef CG_RENDERAREA_H
#define CG_RENDERAREA_H
#include <iostream>
#include <QtOpenGL/QGLWidget>
#include <vcg/space/box3.h>
#include <wrap/gui/trackball.h>
#include <vcg/complex/trimesh/create/ball_pivoting.h>
#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<CMesh> *pivot;
Pivot<CMesh> *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

85
apps/pivoting/main.cpp Normal file
View File

@ -0,0 +1,85 @@
#include <iostream>
using namespace std;
#include <QtGui/QApplication>
#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();
}

465
apps/pivoting/mainwindow.ui Normal file
View File

@ -0,0 +1,465 @@
<ui version="4.0" >
<author></author>
<comment></comment>
<exportmacro></exportmacro>
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>717</width>
<height>727</height>
</rect>
</property>
<property name="palette" >
<palette>
<active>
<color>
<red>128</red>
<green>128</green>
<blue>128</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>127</red>
<green>127</green>
<blue>127</blue>
</color>
<color>
<red>170</red>
<green>170</green>
<blue>170</blue>
</color>
<color>
<red>128</red>
<green>128</green>
<blue>128</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>128</red>
<green>128</green>
<blue>128</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
<color>
<red>49</red>
<green>106</green>
<blue>197</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>0</red>
<green>0</green>
<blue>255</blue>
</color>
<color>
<red>255</red>
<green>0</green>
<blue>255</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</active>
<inactive>
<color>
<red>128</red>
<green>128</green>
<blue>128</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>127</red>
<green>127</green>
<blue>127</blue>
</color>
<color>
<red>170</red>
<green>170</green>
<blue>170</blue>
</color>
<color>
<red>128</red>
<green>128</green>
<blue>128</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>128</red>
<green>128</green>
<blue>128</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
<color>
<red>49</red>
<green>106</green>
<blue>197</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>0</red>
<green>0</green>
<blue>255</blue>
</color>
<color>
<red>255</red>
<green>0</green>
<blue>255</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</inactive>
<disabled>
<color>
<red>128</red>
<green>128</green>
<blue>128</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>127</red>
<green>127</green>
<blue>127</blue>
</color>
<color>
<red>170</red>
<green>170</green>
<blue>170</blue>
</color>
<color>
<red>128</red>
<green>128</green>
<blue>128</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>128</red>
<green>128</green>
<blue>128</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>0</red>
<green>0</green>
<blue>0</blue>
</color>
<color>
<red>49</red>
<green>106</green>
<blue>197</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
<color>
<red>0</red>
<green>0</green>
<blue>255</blue>
</color>
<color>
<red>255</red>
<green>0</green>
<blue>255</blue>
</color>
<color>
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</disabled>
</palette>
</property>
<property name="windowTitle" >
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget" >
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="0" column="1" >
<widget class="QGroupBox" name="groupBox_2" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>1</hsizetype>
<vsizetype>1</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize" >
<size>
<width>120</width>
<height>70</height>
</size>
</property>
<property name="maximumSize" >
<size>
<width>120</width>
<height>300</height>
</size>
</property>
<property name="title" >
<string/>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="9" column="1" >
<widget class="QSpinBox" name="tot" >
<property name="maximum" >
<number>10000000</number>
</property>
<property name="value" >
<number>1</number>
</property>
</widget>
</item>
<item row="9" column="0" >
<widget class="QPushButton" name="add" >
<property name="text" >
<string>Add</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2" >
<widget class="QPushButton" name="add_face" >
<property name="text" >
<string>Add 1 face</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2" >
<widget class="QPushButton" name="add_100_faces" >
<property name="text" >
<string>Add 100 faces</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2" >
<widget class="QPushButton" name="add_10_faces" >
<property name="text" >
<string>Add 10 faces</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2" >
<widget class="QPushButton" name="open" >
<property name="text" >
<string>Open...</string>
</property>
</widget>
</item>
<item row="7" column="0" colspan="2" >
<widget class="QCheckBox" name="smooth" >
<property name="text" >
<string>smooth</string>
</property>
</widget>
</item>
<item row="8" column="1" >
<widget class="QDoubleSpinBox" name="radius" >
<property name="maximum" >
<double>10</double>
</property>
<property name="minimum" >
<double>0.5</double>
</property>
<property name="singleStep" >
<double>0.1</double>
</property>
<property name="value" >
<double>1.2</double>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2" >
<widget class="QPushButton" name="save" >
<property name="text" >
<string>Save</string>
</property>
</widget>
</item>
<item row="8" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>&lt;html>&lt;head>&lt;meta name="qrichtext" content="1" />&lt;/head>&lt;body style=" white-space: pre-wrap; font-family:MS Shell Dlg; font-size:8.25pt; font-weight:400; font-style:normal; text-decoration:none;">&lt;p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">&lt;span style=" font-size:8pt;">R:&lt;/span>&lt;/p>&lt;/body>&lt;/html></string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2" >
<widget class="QPushButton" name="add_1000_faces" >
<property name="text" >
<string>Add 1000 faces</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2" >
<widget class="QPushButton" name="add_all" >
<property name="text" >
<string>Add all</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="1" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::MinimumExpanding</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>271</height>
</size>
</property>
</spacer>
</item>
<item rowspan="2" row="0" column="0" >
<widget class="GLArea" name="area" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>7</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<pixmapfunction></pixmapfunction>
<customwidgets>
<customwidget>
<class>GLArea</class>
<extends>QFrame</extends>
<header>glarea.h</header>
<container>0</container>
<pixmap></pixmap>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

242
apps/pivoting/pivot.dev Normal file
View File

@ -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=

753
apps/pivoting/pivot.h Normal file
View File

@ -0,0 +1,753 @@
#ifndef VCG_PIVOT_H
#define VCG_PIVOT_H
#include <vector>
#include <list>
#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<Hinge>::iterator next;
std::list<Hinge>::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 MESH>
class Pivot {
public:
// typedef CMesh MESH;
typedef GridStaticPtr<typename MESH::VertexType, typename MESH::ScalarType > 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<Hinge> front;
std::list<Hinge> deads;
std::vector<int> 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<int> targets;
std::vector<float> 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<Hinge>::iterator e = front.end();
std::list<Hinge>::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<Hinge>::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<int> 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<Hinge>::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<Hinge>::iterator left = touch;
std::list<Hinge>::iterator right = (*touch).previous;
std::list<Hinge>::iterator up = ei;
if(v1 == (*right).v0 || v0 == (*left).v1) {
// cout << "Bad join.\n";
killHinge(ei);
return 0;
}
nb[v2]++;
std::list<Hinge>::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<Hinge>::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<int> &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<float> 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<Hinge>::iterator newHinge(Hinge e) {
return front.insert(front.end(), e);
}
//move an Hinge among the dead ones
void killHinge(std::list<Hinge>::iterator e) {
deads.splice(deads.end(), front, e);
}
//move an Hinge to the back of the queue
void moveBack(std::list<Hinge>::iterator e) {
front.splice(front.end(), front, e);
}
void moveFront(std::list<Hinge>::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<int> targets;
std::vector<float> 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<Hinge>::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<Hinge>::iterator a, std::list<Hinge>::iterator b) {
if((*a).v0 != (*b).v1) return false;
std::list<Hinge>::iterator previous = (*a).previous;
std::list<Hinge>::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 &center) {
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 &center) {
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<int> &results,
std::vector<float> &dists) {
std::vector<CVertex *> ptr;
std::vector<Point3f> 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 &center) {
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<Hinge>::iterator touches(int v, std::list<Hinge>::iterator e) {
//TODO what happens when it touches more than one front?
//might still work.
std::list<Hinge>::iterator touch = front.end();
if(mesh.vert[v].IsB()) {
//test nearby Hinges: it is faster
std::list<Hinge>::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<Hinge>::iterator k = front.begin(); k != front.end(); k++) {
if(v == (*k).v0) {
touch = k;
break;
}
}
for(std::list<Hinge>::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

129
apps/pivoting/ring.h Normal file
View File

@ -0,0 +1,129 @@
#ifndef RING_H
#define RING_H
// Making a "ring" data structure from the STL
#include <list>
using namespace std;
template<class T>
class ring {
list<T> 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<std::bidirectional_iterator_tag, T, ptrdiff_t> {
public:
typename list<T>::iterator it;
list<T>* r;
// "typename" necessary to resolve nesting:
iterator(): r(NULL) {}
iterator(list<T>& lst, const typename list<T>::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<T>::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<T>::iterator it;
it = lst.insert(i.it, x);
return iterator(lst, it);
}
iterator push_back(const T& x) {
typename list<T>::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