forked from bartvdbraak/blender
280 lines
6.1 KiB
C++
280 lines
6.1 KiB
C++
/*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* 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 for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
* All rights reserved.
|
|
*
|
|
* The Original Code is: all of this file.
|
|
*
|
|
* Contributor(s): none yet.
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
/** \file decimation/intern/LOD_QuadricEditor.cpp
|
|
* \ingroup decimation
|
|
*/
|
|
|
|
|
|
#include "LOD_QuadricEditor.h"
|
|
#include "LOD_ExternNormalEditor.h"
|
|
|
|
// Creation
|
|
///////////
|
|
|
|
using namespace std;
|
|
|
|
|
|
LOD_QuadricEditor::
|
|
LOD_QuadricEditor(
|
|
LOD_ManMesh2 &mesh
|
|
) :
|
|
m_quadrics(NULL),
|
|
m_mesh(mesh)
|
|
{
|
|
};
|
|
|
|
LOD_QuadricEditor *
|
|
LOD_QuadricEditor::
|
|
New(
|
|
LOD_ManMesh2 &mesh
|
|
){
|
|
//same number of quadrics as vertices in the mesh
|
|
|
|
MEM_SmartPtr<LOD_QuadricEditor> output(new LOD_QuadricEditor(mesh));
|
|
|
|
if (output == NULL) {
|
|
return NULL;
|
|
}
|
|
return output.Release();
|
|
}
|
|
|
|
|
|
// Property editor interface
|
|
////////////////////////////
|
|
|
|
void
|
|
LOD_QuadricEditor::
|
|
Remove(
|
|
std::vector<LOD_VertexInd> &sorted_vertices
|
|
){
|
|
vector<LOD_Quadric> & quadrics = *m_quadrics;
|
|
|
|
vector<LOD_VertexInd>::const_iterator it_start = sorted_vertices.begin();
|
|
vector<LOD_VertexInd>::const_iterator it_end = sorted_vertices.end();
|
|
|
|
for (; it_start != it_end; ++it_start) {
|
|
|
|
if (quadrics.size() > 0) {
|
|
LOD_Quadric temp = quadrics[*it_start];
|
|
|
|
quadrics[*it_start] = quadrics.back();
|
|
quadrics.back() = temp;
|
|
|
|
quadrics.pop_back();
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
// Editor specific methods
|
|
//////////////////////////
|
|
|
|
bool
|
|
LOD_QuadricEditor::
|
|
BuildQuadrics(
|
|
LOD_ExternNormalEditor& normal_editor,
|
|
bool preserve_boundaries
|
|
){
|
|
if (m_quadrics != NULL) delete(m_quadrics);
|
|
|
|
m_quadrics =new vector<LOD_Quadric> (m_mesh.VertexSet().size());
|
|
if (m_quadrics == NULL) return false;
|
|
|
|
// iterate through the face set of the mesh
|
|
// compute a quadric based upon that face and
|
|
// add it to each of it's vertices quadrics.
|
|
|
|
const vector<LOD_TriFace> &faces = m_mesh.FaceSet();
|
|
const vector<LOD_Vertex> &verts = m_mesh.VertexSet();
|
|
vector<LOD_Edge> &edges = m_mesh.EdgeSet();
|
|
|
|
const vector<MT_Vector3> &normals = normal_editor.Normals();
|
|
vector<MT_Vector3>::const_iterator normal_it = normals.begin();
|
|
|
|
vector<LOD_TriFace>::const_iterator face_it = faces.begin();
|
|
vector<LOD_TriFace>::const_iterator face_end = faces.end();
|
|
|
|
vector<LOD_Quadric> & quadrics = *m_quadrics;
|
|
|
|
|
|
for (; face_it != face_end; ++face_it, ++normal_it) {
|
|
|
|
MT_Vector3 normal = *normal_it;
|
|
MT_Scalar offset = -normal.dot(verts[face_it->m_verts[0]].pos);
|
|
|
|
LOD_Quadric q(normal,offset);
|
|
|
|
quadrics[face_it->m_verts[0]] += q;
|
|
quadrics[face_it->m_verts[1]] += q;
|
|
quadrics[face_it->m_verts[2]] += q;
|
|
}
|
|
|
|
if (preserve_boundaries) {
|
|
|
|
// iterate through the edge set and add a boundary quadric to
|
|
// each of the boundary edges vertices.
|
|
|
|
vector<LOD_Edge>::const_iterator edge_it = edges.begin();
|
|
vector<LOD_Edge>::const_iterator edge_end = edges.end();
|
|
|
|
for (; edge_it != edge_end; ++edge_it) {
|
|
if (edge_it->BoundaryEdge()) {
|
|
|
|
// compute a plane perpendicular to the edge and the normal
|
|
// of the edges single polygon.
|
|
const MT_Vector3 & v0 = verts[edge_it->m_verts[0]].pos;
|
|
const MT_Vector3 & v1 = verts[edge_it->m_verts[1]].pos;
|
|
|
|
MT_Vector3 edge_vector = v1 - v0;
|
|
|
|
LOD_FaceInd edge_face = edge_it->OpFace(LOD_EdgeInd::Empty());
|
|
edge_vector = edge_vector.cross(normals[edge_face]);
|
|
|
|
if (!edge_vector.fuzzyZero()) {
|
|
edge_vector.normalize();
|
|
|
|
LOD_Quadric boundary_q(edge_vector, - edge_vector.dot(v0));
|
|
boundary_q *= 100;
|
|
|
|
quadrics[edge_it->m_verts[0]] += boundary_q;
|
|
quadrics[edge_it->m_verts[1]] += boundary_q;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// initiate the heap keys of the edges by computing the edge costs.
|
|
|
|
vector<LOD_Edge>::iterator edge_it = edges.begin();
|
|
vector<LOD_Edge>::const_iterator edge_end = edges.end();
|
|
|
|
for (; edge_it != edge_end; ++edge_it) {
|
|
|
|
MT_Vector3 target = TargetVertex(*edge_it);
|
|
|
|
LOD_Edge &e = *edge_it;
|
|
LOD_Quadric q0 = quadrics[e.m_verts[0]];
|
|
const LOD_Quadric &q1 = quadrics[e.m_verts[1]];
|
|
|
|
e.HeapKey() = -float(q0.Evaluate(target) + q1.Evaluate(target));
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
MT_Vector3
|
|
LOD_QuadricEditor::
|
|
TargetVertex(
|
|
LOD_Edge & e
|
|
){
|
|
|
|
// compute an edge contration target for edge ei
|
|
// this is computed by summing it's vertices quadrics and
|
|
// optimizing the result.
|
|
vector<LOD_Vertex> &verts = m_mesh.VertexSet();
|
|
|
|
vector<LOD_Quadric> &quadrics = *m_quadrics;
|
|
|
|
LOD_VertexInd v0 = e.m_verts[0];
|
|
LOD_VertexInd v1 = e.m_verts[1];
|
|
|
|
LOD_Quadric q0 = quadrics[v0];
|
|
q0 += quadrics[v1];
|
|
|
|
MT_Vector3 result;
|
|
|
|
if (q0.Optimize(result)) {
|
|
return result;
|
|
} else {
|
|
// the quadric was degenerate -> just take the average of
|
|
// v0 and v1
|
|
|
|
return ((verts[v0].pos + verts[v1].pos) * 0.5);
|
|
}
|
|
};
|
|
|
|
void
|
|
LOD_QuadricEditor::
|
|
ComputeEdgeCosts(
|
|
vector<LOD_EdgeInd> &edges
|
|
){
|
|
|
|
// for each we compute the target vertex and then compute
|
|
// the quadric error e = Q1(v') + Q2(v')
|
|
vector<LOD_Edge> &edge_set = m_mesh.EdgeSet();
|
|
|
|
vector<LOD_Quadric> &quadrics = *m_quadrics;
|
|
|
|
vector<LOD_EdgeInd>::const_iterator edge_it = edges.begin();
|
|
vector<LOD_EdgeInd>::const_iterator edge_end = edges.end();
|
|
|
|
for (; edge_it != edge_end; ++edge_it) {
|
|
|
|
MT_Vector3 target = TargetVertex(edge_set[*edge_it]);
|
|
|
|
LOD_Edge &e = edge_set[*edge_it];
|
|
LOD_Quadric q0 = quadrics[e.m_verts[0]];
|
|
const LOD_Quadric &q1 = quadrics[e.m_verts[1]];
|
|
|
|
e.HeapKey() = -float(q0.Evaluate(target) + q1.Evaluate(target));
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|