mirror of
https://github.com/lucaspalomodevelop/meshlab.git
synced 2026-03-14 08:34:37 +00:00
662 lines
20 KiB
C++
662 lines
20 KiB
C++
/****************************************************************************
|
||
* MeshLab o o *
|
||
* A versatile mesh processing toolbox o o *
|
||
* _ O _ *
|
||
* Copyright(C) 2005 \/)\/ *
|
||
* Visual Computing Lab /\/| *
|
||
* ISTI - Italian National Research Council | *
|
||
* \ *
|
||
* All rights reserved. *
|
||
* *
|
||
* This program is free software; you can redistribute it and/or modify *
|
||
* it under the terms of the GNU General Public License as published by *
|
||
* the Free Software Foundation; either version 2 of the License, or *
|
||
* (at your option) any later version. *
|
||
* *
|
||
* This program 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 General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
||
* for more details. *
|
||
* *
|
||
****************************************************************************/
|
||
|
||
#ifndef EDITPAINT_H
|
||
#define EDITPAINT_H
|
||
|
||
#include <GL/glew.h>
|
||
#include <QObject>
|
||
#include <QDockWidget>
|
||
|
||
#include <meshlab/glarea.h>
|
||
#include <common/plugins/interfaces/edit_plugin.h>
|
||
#include <wrap/gl/pick.h>
|
||
|
||
#include "paintbox.h"
|
||
|
||
/**
|
||
* These options are chosen by each tool in the method setToolType(TolType t)
|
||
*/
|
||
enum PaintOptions {
|
||
EPP_NONE = 0x00000,
|
||
EPP_PICK_FACES = 0x00001, //On press, pick faces
|
||
EPP_PICK_VERTICES = 0x00003, //On press, find the vertices (implies face picking too)
|
||
EPP_AVG_NORMAL = 0x00007, //During vertex picking, find the average normal of all vertices (implies vertex picking)
|
||
EPP_DRAW_CURSOR = 0x00008 //On mouse move display a shape representing the given cursor
|
||
};
|
||
|
||
|
||
/**
|
||
* EditPaint plugin main class (MeshEditing plugin)
|
||
*/
|
||
class EditPaintPlugin : public QObject, public EditTool {
|
||
Q_OBJECT
|
||
|
||
public:
|
||
EditPaintPlugin();
|
||
virtual ~EditPaintPlugin();
|
||
|
||
static const QString info();
|
||
|
||
void suggestedRenderingData(MeshModel &/*m*/, MLRenderingData& /*dt*/);
|
||
bool startEdit(MeshModel &/*m*/, GLArea * /*parent*/, MLSceneGLSharedDataContext* /*cont*/);
|
||
void endEdit(MeshModel &/*m*/, GLArea * /*parent*/, MLSceneGLSharedDataContext* /*cont*/);
|
||
void decorate(MeshModel &/*m*/, GLArea * /*parent*/);
|
||
void mousePressEvent(QMouseEvent *event, MeshModel &/*m*/, GLArea *);
|
||
void mouseMoveEvent(QMouseEvent *event, MeshModel &/*m*/, GLArea *);
|
||
void mouseReleaseEvent(QMouseEvent *event, MeshModel &/*m*/, GLArea *);
|
||
void tabletEvent(QTabletEvent *, MeshModel &, GLArea *);
|
||
|
||
|
||
signals:
|
||
void setSelectionRendering(bool);
|
||
|
||
public slots:
|
||
void update();
|
||
void setToolType(ToolType t);
|
||
void setBrushSettings(int size, int opacity, int hardness);
|
||
|
||
private:
|
||
struct PickingData { QPoint position; QPointF rel_position; float distance; };
|
||
|
||
void updateSelection(MeshModel &m, std::vector< std::pair<CVertexO *, PickingData> > * vertex_result = NULL);
|
||
void updateColorBuffer(MeshModel& m,MLSceneGLSharedDataContext* shared);
|
||
void updateGeometryBuffers(MeshModel& m,MLSceneGLSharedDataContext* shared);
|
||
|
||
double modelview_matrix[16]; //modelview
|
||
double projection_matrix[16]; //projection
|
||
GLint viewport[4];
|
||
|
||
GLArea * glarea;
|
||
GLfloat* zbuffer; /*< last known zbuffer, always kept up-to-date */
|
||
|
||
QDockWidget* dock;
|
||
Paintbox* paintbox; /*< The current Paintbox*/
|
||
|
||
std::vector<CMeshO::FacePointer> * selection; //currently selected faces
|
||
std::vector< std::pair<CVertexO *, PickingData> > vertices; //touched vertices during last updateSelection
|
||
Point3m normal; //average normal of all vertices in "vertices"
|
||
|
||
std::vector<QPointF> circle;
|
||
std::vector<QPointF> dense_circle;
|
||
std::vector<QPointF> square;
|
||
std::vector<QPointF> dense_square;
|
||
|
||
//New code under this line---
|
||
|
||
//Memoization of type and type-settings
|
||
ToolType current_type;
|
||
int current_options;
|
||
|
||
//Input Events Handling:
|
||
struct InputEvent {
|
||
Qt::MouseButton button;
|
||
QEvent::Type type;
|
||
QPoint position;
|
||
QPoint gl_position;
|
||
Qt::KeyboardModifiers modifiers;
|
||
qreal pressure;
|
||
bool processed;
|
||
bool valid;
|
||
};
|
||
|
||
InputEvent latest_event;
|
||
InputEvent previous_event;
|
||
|
||
inline void pushInputEvent(QEvent::Type t, QPoint p,
|
||
Qt::KeyboardModifiers k, qreal pres, Qt::MouseButton b, GLArea * gla)
|
||
{
|
||
if (latest_event.processed) previous_event = latest_event;
|
||
|
||
latest_event.type = t;
|
||
latest_event.position = p;
|
||
latest_event.gl_position = QPoint(p.x(), gla->height() - p.y());
|
||
latest_event.modifiers = k;
|
||
latest_event.button = b;
|
||
latest_event.pressure = pres;
|
||
latest_event.processed = false;
|
||
latest_event.valid = true;
|
||
}
|
||
|
||
//Brush frequently accessed setting memoization
|
||
struct Brush {
|
||
int size;
|
||
int opacity;
|
||
int hardness;
|
||
float radius;
|
||
bool size_map;
|
||
bool opacity_map;
|
||
bool hardness_map;
|
||
};
|
||
|
||
Brush current_brush;
|
||
|
||
/****** Painting, Cloning and Noise Tools ******/
|
||
void paint(std::vector< std::pair<CVertexO *, PickingData> > * vertices);
|
||
void capture();
|
||
bool accessCloneBuffer(int, int, vcg::Color4b &);
|
||
void computeNoiseColor(CVertexO *, vcg::Color4b &);
|
||
QHash<CVertexO *, std::pair<vcg::Color4b, int> > painted_vertices; /*<active vertices during painting */
|
||
|
||
vcg::Color4b color;
|
||
|
||
GLubyte* color_buffer; /*< buffer used as color source in cloning*/
|
||
GLfloat* clone_zbuffer; /*<buffer to determine if the source is legal or not */
|
||
QPoint clone_delta;
|
||
QPoint source_delta;
|
||
QPoint apply_start;
|
||
int buffer_width;
|
||
int buffer_height;
|
||
|
||
float noise_scale;
|
||
/****** Pull and Push Tools ******/
|
||
void sculpt(MeshModel &, std::vector< std::pair<CVertexO *, PickingData> > * vertices);
|
||
|
||
QHash<CVertexO *, std::pair<vcg::Point3f, float> > displaced_vertices; /*<active vertices during sculpting */
|
||
|
||
|
||
/****** Gradient Tool ******/
|
||
void gradient(MeshModel & m, GLArea * gla);
|
||
|
||
QPoint gradient_start;
|
||
|
||
|
||
/****** Color and Position Smoothing ******/
|
||
void smooth(std::vector< std::pair<CVertexO *, PickingData> > * vertices);
|
||
QHash<CVertexO *, CVertexO *> smoothed_vertices;
|
||
|
||
/****** Color Fill ******/
|
||
void fill(MeshModel & m, CFaceO * face);
|
||
};
|
||
|
||
/**
|
||
* Undo Class to store color changes. Intergrates in the Qt Undo framework.
|
||
* Undoes the change to a single vertex only. Must use the Command compression
|
||
* system by Qt.
|
||
* What if the vertex has been deleted in the meantime?
|
||
*/
|
||
class SingleColorUndo : public QUndoCommand
|
||
{
|
||
|
||
public:
|
||
SingleColorUndo(CVertexO * v, vcg::Color4b c,QUndoCommand * parent = 0) : QUndoCommand(parent) {
|
||
vertex = v;
|
||
original = c; // setText("Single Vertex Color Change");
|
||
}
|
||
|
||
virtual void undo() override
|
||
{
|
||
vcg::Color4b temp = vertex->C();
|
||
vertex->C() = original;
|
||
original = temp;
|
||
}
|
||
virtual void redo() override { undo(); }
|
||
virtual int id() const override { return COLOR_PAINT; }
|
||
|
||
private:
|
||
CVertexO* vertex;
|
||
vcg::Color4b original;
|
||
};
|
||
|
||
//TODO Create MultipleColorUndo
|
||
|
||
class SinglePositionUndo : public QUndoCommand
|
||
{
|
||
|
||
public:
|
||
SinglePositionUndo(CVertexO * v, Point3m p, Point3m n, QUndoCommand * parent = 0) : QUndoCommand(parent) {
|
||
vertex = v; original = p; normal = n;
|
||
}
|
||
|
||
virtual void undo() override {
|
||
Point3m temp = vertex->P(); vertex->P() = original; original = temp;
|
||
temp = vertex->N(); vertex->N() = normal; normal = temp;
|
||
}
|
||
virtual void redo() override { undo(); }
|
||
virtual int id() const override { return MESH_PULL; }
|
||
|
||
private:
|
||
CVertexO* vertex;
|
||
Point3m original;
|
||
Point3m normal;
|
||
};
|
||
|
||
|
||
/**
|
||
* Undoes changes in selected faces.
|
||
*
|
||
* Same doubt as above about vertex deletion!
|
||
*/
|
||
class SelectionUndo : public QUndoCommand
|
||
{
|
||
public:
|
||
SelectionUndo(CFaceO * f, bool sel, QUndoCommand * parent = 0) : QUndoCommand(parent) {
|
||
face = f; original = sel; // setText("Single Vertex Color Change");
|
||
}
|
||
|
||
virtual void undo() override { bool temp = face->IsS(); original ? face->SetS() : face->ClearS(); original = temp; }
|
||
virtual void redo() override { undo(); }
|
||
virtual int id() const override { return MESH_SELECT; }
|
||
private:
|
||
CFaceO * face;
|
||
bool original;
|
||
};
|
||
|
||
/*********Generic Utility Routines************/
|
||
|
||
/**
|
||
* Colorizes a vertex with the new color.
|
||
|
||
* Has been converted in a for loop. No performance
|
||
* loss since compiler will unroll constant loops
|
||
*
|
||
* O(1) complexity
|
||
*/
|
||
inline void applyColor(CVertexO * vertex, const vcg::Color4b& newcol, int opac)
|
||
{
|
||
vcg::Color4b orig = vertex->C();
|
||
|
||
opac *= ((float)newcol[3] / 255.0);
|
||
|
||
for (int i = 0; i < 3; i++)
|
||
orig[i] = std::min(255, ((newcol[i] - orig[i]) * opac + orig[i] * 100) / 100);
|
||
|
||
vertex->C() = orig;
|
||
}
|
||
|
||
/**
|
||
* Same modification as above
|
||
*
|
||
* O(1) complexity
|
||
*/
|
||
inline void mergeColors(double percent, const vcg::Color4b& c1, const vcg::Color4b& c2, vcg::Color4b* dest)
|
||
{
|
||
for (int i = 0; i < 4; i++)
|
||
(*dest)[i] = (char)std::min(255.0, ((c1[i] - c2[i])*percent + c2[i]));
|
||
}
|
||
|
||
/**
|
||
* The weighted average of the two vectors c1 and c2 is
|
||
* stored in dest. c1's weight is given by percent, while
|
||
* c2's weight is given by 1.0 - percent
|
||
*
|
||
* Can actually merge any 3d array, not just positions
|
||
*/
|
||
inline void mergePositions(double percent, const float c1[3], const float c2[3], float dest[3])
|
||
{
|
||
for (int i = 0; i < 3; i++)
|
||
dest[i] = c1[i] * percent + c2[i] * (1.0 - percent);
|
||
}
|
||
|
||
/*********Geometric Utility Routines************/
|
||
|
||
/**
|
||
* Quickly ransforms a 3 point with a 44 matrix,
|
||
* avoiding unnecessary computations (the w component is
|
||
* assumed to be 1)
|
||
*
|
||
* Original Code by Gfrei Andreas
|
||
*/
|
||
inline void fastMultiply(float x, float y, float z, double matrix[], double *xr, double *yr, double *zr)
|
||
{
|
||
*xr = x * matrix[0] + y * matrix[4] + z * matrix[8] + matrix[12];
|
||
*yr = x * matrix[1] + y * matrix[5] + z * matrix[9] + matrix[13];
|
||
*zr = x * matrix[2] + y * matrix[6] + z * matrix[10] + matrix[14];
|
||
}
|
||
|
||
/**
|
||
* Finds the nearest point to "center" among "points".
|
||
*
|
||
* O(num)
|
||
*/
|
||
inline int getNearest(QPointF center, QPointF *points, int num)
|
||
{
|
||
using std::abs;
|
||
int index = 0;
|
||
|
||
float dist = abs(center.x() - points[0].x())*abs(center.x() - points[0].x()) + abs(center.y() - points[0].y())*abs(center.y() - points[0].y());
|
||
|
||
float temp = 0;
|
||
|
||
for (int i = 1; i < num; i++)
|
||
{
|
||
temp = abs(center.x() - points[i].x())*abs(center.x() - points[i].x()) +
|
||
abs(center.y() - points[i].y())*abs(center.y() - points[i].y());
|
||
|
||
if (temp < dist) {
|
||
index = i;
|
||
dist = temp;
|
||
}
|
||
}
|
||
return index;
|
||
}
|
||
|
||
/**
|
||
* Checks if a point (x, y) is contained in either:
|
||
*
|
||
* a) the rectangle aligned to the segment connecting p0 to p1
|
||
* whose height is the distance between p0 and p1 and width
|
||
* is radius * 2
|
||
* b) the circle centered in p0 with given radius
|
||
* c) the circle centered in p1 with same radius
|
||
*
|
||
* To check condition (a): let v be the vector going from p0 to p1
|
||
* and w the vector from p0 to (x, y). If theta is the angle between
|
||
* v and w, then:
|
||
*
|
||
* |v| |w| cos(theta) |w|
|
||
* r = ------------------ = --- cos(theta)
|
||
* |v|² |v|
|
||
*
|
||
* is the ratio between the length of vector v and the projection
|
||
* of vector w on vector v.
|
||
*
|
||
* Since w' = v * r is the projection of w on v, pf = p0 + w' is
|
||
* the orthogonal projection of (x, y) on the segment
|
||
* connecting p0 to p1. If the distance between (x, y) and pf is less
|
||
* than radius, then (x, y) lays inside the rectangle
|
||
*
|
||
*/
|
||
inline bool isIn(const QPointF &p0, const QPointF &p1, float x, float y, float radius, float *dist, QPointF &pos)
|
||
{
|
||
float radius_sq = radius * radius;
|
||
|
||
if (p0 != p1) //otherwise condition (a) needs not to be tested: rectangle is null
|
||
{
|
||
float v_x = (p1.x() - p0.x());
|
||
float v_y = (p1.y() - p0.y());
|
||
|
||
float v_length_squared = v_x * v_x + v_y * v_y;
|
||
|
||
float w_x = x - p0.x();
|
||
float w_y = y - p0.y();
|
||
|
||
float v_dot_w = w_x * v_x + w_y * v_y; //scalar product of v and w
|
||
|
||
float r = v_dot_w / v_length_squared;
|
||
|
||
float pf_x = p0.x() + r * v_x;
|
||
float pf_y = p0.y() + r * v_y;
|
||
|
||
float delta_x = x - pf_x;
|
||
float delta_y = y - pf_y;
|
||
|
||
if (r >= 0 && r <= 1 && (delta_x * delta_x + delta_y * delta_y < radius_sq))
|
||
{
|
||
float delta_len = sqrt(delta_x * delta_x + delta_y * delta_y);
|
||
|
||
*dist = delta_len / radius;
|
||
pos.setY(delta_y / radius);
|
||
pos.setX(delta_x / radius);
|
||
return true;
|
||
}
|
||
}
|
||
|
||
// there could be some problem when point is nearer p0 or p1 and viceversa
|
||
// so i have to check both. is only needed with smooth_borders
|
||
bool found = false;
|
||
float dx = (x - p1.x());
|
||
float dy = (y - p1.y());
|
||
float delta_len_sq = dx*dx + dy*dy;
|
||
|
||
if (delta_len_sq < radius_sq)
|
||
{
|
||
float delta_len = sqrt(delta_len_sq);
|
||
*dist = delta_len;
|
||
pos.setY(dy / radius);
|
||
pos.setX(dx / radius);
|
||
found = true;
|
||
}
|
||
|
||
if (p0 == p1) {
|
||
*dist /= radius;
|
||
return found;
|
||
}
|
||
|
||
dx = (x - p0.x());
|
||
dy = (y - p0.y());
|
||
delta_len_sq = dx*dx + dy*dy;
|
||
|
||
if (delta_len_sq < radius_sq)
|
||
{
|
||
float delta_len = sqrt(delta_len_sq);
|
||
if ((found && delta_len < *dist) || !found)
|
||
{
|
||
*dist = delta_len;
|
||
// pos.setY(x / delta_len );
|
||
pos.setY(dy / radius);
|
||
pos.setX(dx / radius);
|
||
}
|
||
found = true;
|
||
}
|
||
|
||
*dist /= radius;
|
||
|
||
return found;
|
||
}
|
||
|
||
inline bool pointInTriangle(const float p_x, const float p_y, const float a_x, const float a_y,
|
||
const float b_x, const float b_y, const float c_x, const float c_y)
|
||
{
|
||
float fab = (p_y - a_y)*(b_x - a_x) - (p_x - a_x)*(b_y - a_y);
|
||
float fbc = (p_y - c_y)*(a_x - c_x) - (p_x - c_x)*(a_y - c_y);
|
||
float fca = (p_y - b_y)*(c_x - b_x) - (p_x - b_x)*(c_y - b_y);
|
||
if (fab*fbc > 0 && fbc*fca > 0) return true;
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* checks if a point is in a triangle (2D)
|
||
*/
|
||
inline bool pointInTriangle(const QPointF &p, const QPointF &a, const QPointF &b, const QPointF &c)
|
||
{
|
||
return pointInTriangle(p.x(), p.y(), a.x(), a.y(), b.x(), b.y(), c.x(), c.y());
|
||
}
|
||
|
||
/**
|
||
* checks if a triangle is front or backfaced
|
||
*/
|
||
inline bool isFront(const float a_x, const float a_y, const float b_x, const float b_y, const float c_x, const float c_y) {
|
||
return (b_x - a_x)*(c_y - a_y) - (b_y - a_y)*(c_x - a_x) > 0;
|
||
}
|
||
|
||
/**
|
||
* checks if a triangle is front or backfaced
|
||
*/
|
||
inline bool isFront(const QPointF &a, const QPointF &b, const QPointF &c) {
|
||
return isFront(a.x(), a.y(), b.x(), b.y(), c.x(), c.y());
|
||
}
|
||
|
||
|
||
/**
|
||
* Checks if a line from LineStart to LineEnd intersects the circle defined
|
||
* by CircleCenter and Radius in one or two points.
|
||
*
|
||
* pOut will either store
|
||
* a) LineStart, if it is inside the circle
|
||
* b) The one intersection between the line and the circle
|
||
* c) One of the two intersections
|
||
*
|
||
* Let L(t) = LineStart + (t * Direction) the parametric equation
|
||
* of the line, with 0 <= t <= 1 and Dircetion = LineEnd - LineStart
|
||
*
|
||
* Let |P - CircleCenter|² = radius² be the equation of the circle. Then, substituting L(t) to P
|
||
*
|
||
* |LineStart + (t * Direction) - CircleCenter|² = radius²
|
||
*
|
||
* Let Delta be LineStart - CircleCenter, then the equation above becomes
|
||
*
|
||
* t² * |Direction|² + 2 * t * (Direction · Delta) + |Delta|² - radius² = 0
|
||
*
|
||
* whose determinant is
|
||
*
|
||
* d = (Direction · Delta)² − |Direction|²(|Delta|² − radius²)
|
||
*
|
||
* if d < 0 there are no intersection, if d = 0 there is one, if d > 0 there are two.
|
||
*/
|
||
inline bool lineHitsCircle(QPointF& LineStart, QPointF& LineEnd, QPointF& CircleCenter, float radius)
|
||
{
|
||
const float radius_sq = radius * radius;
|
||
QPointF Delta = LineStart - CircleCenter;
|
||
|
||
float delta_length_sq = Delta.x()*Delta.x() + Delta.y()*Delta.y();
|
||
|
||
if (delta_length_sq <= radius_sq) return true;
|
||
|
||
QPointF Direction = LineEnd - LineStart;
|
||
|
||
const float direction_dot_delta = Direction.x()*Delta.x() + Direction.y()*Delta.y();
|
||
|
||
const float direction_length_sq = Direction.x()*Direction.x() + Direction.y()*Direction.y();
|
||
|
||
const float d = (direction_dot_delta * direction_dot_delta) - direction_length_sq * (delta_length_sq - radius_sq);
|
||
|
||
if (d < 0.0f) return false; //no intersection
|
||
else if (d < 0.0001f) //one intersection
|
||
{
|
||
const float s = -direction_dot_delta / direction_length_sq;
|
||
if (s < 0.0f || s > 1.0f) return false;
|
||
else return true;
|
||
}
|
||
else //two intersections
|
||
{
|
||
const float s = (-direction_dot_delta - sqrtf(d)) / direction_length_sq; //only one intersection is chosen
|
||
if (s < 0.0f || s > 1.0f) return false;
|
||
else return true;
|
||
}
|
||
}
|
||
|
||
/*********CMeshO Utility Routines************/
|
||
|
||
/**
|
||
* Simple displacement of vertex along its normal. Make sure normals
|
||
* are precomputed!!
|
||
*
|
||
* O(1)
|
||
*/
|
||
inline void displaceAlongVector(CVertexO* vp, Point3m vector, float displacement)
|
||
{
|
||
(*vp).P() += vector * displacement;
|
||
}
|
||
|
||
/**
|
||
* Get the vertex currently pointed by the mouse at position cursor on the mesh m
|
||
* This vertex is obtained by first finding the face nearest to the mouse, and then
|
||
* finding the nearest vertex to the cursor among the face vertices.
|
||
*
|
||
* Same complexity as GLPickTri<CMeshO>::PickNearestFace(..)
|
||
*/
|
||
inline bool getVertexAtMouse(MeshModel &m, CMeshO::VertexPointer& value, QPoint& cursor,
|
||
double* modelview_matrix, double* projection_matrix, GLint* viewport)
|
||
{
|
||
|
||
double tx, ty, tz;
|
||
|
||
//TODO e se i vertici sono stati cancellati? (IsD())
|
||
std::vector<CFaceO*> res;
|
||
int nface = vcg::GLPickTri<CMeshO>::PickVisibleFace(cursor.x(), cursor.y(), m.cm, res, 2, 2);
|
||
//if (GLPickTri<CMeshO>::PickClosestFace(latest_event.gl_position.x(), latest_event.gl_position.y(), m.cm, face, 2, 2))
|
||
if ((nface > 0) && (res[0] != NULL) && !(res[0]->IsD()))
|
||
//if (vcg::GLPickTri<CMeshO>::PickClosestFace(cursor.x(), cursor.y(), m.cm, fp, 2, 2))
|
||
{
|
||
CFaceO * fp = res[0];
|
||
QPointF point[3];
|
||
|
||
for (int i = 0; i < 3; i++)
|
||
{
|
||
gluProject(fp->V(i)->P()[0], fp->V(i)->P()[1], fp->V(i)->P()[2],
|
||
modelview_matrix,
|
||
projection_matrix,
|
||
viewport,
|
||
&tx, &ty, &tz);
|
||
|
||
point[i] = QPointF(tx, ty);
|
||
}
|
||
|
||
value = fp->V(getNearest(cursor, point, 3));
|
||
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
|
||
/**
|
||
* calcs the surrounding faces of a vertex with VF topology
|
||
*/
|
||
inline void getSurroundingFacesVF(CFaceO * fac, int vert_pos, std::vector<CFaceO *> *surround) {
|
||
CVertexO * vert = fac->V(vert_pos);
|
||
int pos = vert->VFi();
|
||
CFaceO * first_fac = vert->VFp();
|
||
CFaceO * curr_f = first_fac;
|
||
do {
|
||
CFaceO * temp = curr_f->VFp(pos);
|
||
if (curr_f != 0 && !curr_f->IsD()) {
|
||
surround->push_back(curr_f);
|
||
pos = curr_f->VFi(pos);
|
||
}
|
||
curr_f = temp;
|
||
} while (curr_f != first_fac && curr_f != 0);
|
||
}
|
||
|
||
inline bool hasSelected(MeshModel &m) {
|
||
CMeshO::FaceIterator fi;
|
||
for (fi = m.cm.face.begin(); fi != m.cm.face.end(); fi++) {
|
||
if (!(*fi).IsD() && (*fi).IsS()) return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
inline void updateNormal(CVertexO * v)
|
||
{
|
||
CFaceO * f = v->VFp();
|
||
CFaceO * one_face = f;
|
||
int pos = v->VFi();
|
||
v->N()[0] = 0; v->N()[1] = 0; v->N()[2] = 0;
|
||
do {
|
||
CFaceO * temp = one_face->VFp(pos);
|
||
if (one_face != 0 && !one_face->IsD())
|
||
{
|
||
one_face->N() = TriangleNormal(*one_face).Normalize();
|
||
v->N() += one_face->N();
|
||
pos = one_face->VFi(pos);
|
||
}
|
||
one_face = temp;
|
||
} while (one_face != f && one_face != 0);
|
||
v->N().Normalize();
|
||
}
|
||
|
||
/*********OpenGL Drawing Routines************/
|
||
|
||
|
||
void drawNormalPercentualCircle(GLArea *, QPoint &, MeshModel &, GLfloat*, double*, double*, GLint*, float);
|
||
void drawVertex(CVertexO*);
|
||
void drawLine(GLArea *, QPoint &, QPoint &);
|
||
void drawSimplePolyLine(GLArea * gla, QPoint & gl_cur, float scale, std::vector<QPointF> * points);
|
||
void drawPercentualPolyLine(GLArea *, QPoint &, MeshModel &, GLfloat*, double*, double*, GLint*, float, std::vector<QPointF> *);
|
||
|
||
void generateCircle(std::vector<QPointF> &, int segments = 18);
|
||
void generateSquare(std::vector<QPointF> &, int segments = 1);
|
||
|
||
#endif
|