Blender  V2.59
LOD_NdQSDecimator.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: LOD_NdQSDecimator.cpp 35147 2011-02-25 10:47:28Z jesterking $
00003  * ***** BEGIN GPL LICENSE BLOCK *****
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * as published by the Free Software Foundation; either version 2
00008  * of the License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software Foundation,
00017  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018  *
00019  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00020  * All rights reserved.
00021  *
00022  * The Original Code is: all of this file.
00023  *
00024  * Contributor(s): none yet.
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  */
00028 
00034 #include "LOD_NdQSDecimator.h"
00035 
00036 #include "LOD_ExternBufferEditor.h"
00037 #include "LOD_ExternNormalEditor.h"
00038 #include "LOD_ExternVColorEditor.h"
00039 #include "TNT/lu.h"
00040 
00041 #include <iostream>
00042 
00043 using namespace std;
00044 
00045         LOD_NdQSDecimator *
00046 LOD_NdQSDecimator::
00047 New(
00048         LOD_ManMesh2 &mesh,
00049         LOD_ExternNormalEditor &face_editor,
00050         LOD_ExternVColorEditor &color_editor,
00051         LOD_ExternBufferEditor &extern_editor
00052 ){
00053 
00054         NanPtr<LOD_NdQSDecimator> output 
00055                 = new LOD_NdQSDecimator(mesh,face_editor,color_editor,extern_editor);
00056 
00057         NanPtr<LOD_EdgeCollapser > collapser(LOD_EdgeCollapser::New());
00058         NanPtr<LOD_NdQuadricEditor> q_editor(LOD_NdQuadricEditor::New(mesh));
00059 
00060         if (
00061                 output == NULL ||
00062                 collapser == NULL ||
00063                 q_editor == NULL 
00064         ) {
00065                 return NULL;
00066         }
00067         output->m_collapser = collapser.Release();
00068         output->m_quadric_editor = q_editor.Release();
00069         return output.Release();
00070 }       
00071 
00072 
00073 
00074         bool
00075 LOD_NdQSDecimator::
00076 Arm(
00077 ){
00078         MT_assert(!m_is_armed);
00079         bool heap_result = BuildHeap();
00080         if (!heap_result) {
00081                 return false;
00082         }
00083         m_is_armed = true;
00084         return true;
00085 }
00086         
00087         bool
00088 LOD_NdQSDecimator::
00089 Step(
00090 ){
00091         return CollapseEdge();
00092 }
00093 
00094 
00095 LOD_NdQSDecimator::
00096 LOD_NdQSDecimator(
00097         LOD_ManMesh2 &mesh,
00098         LOD_ExternNormalEditor &face_editor,
00099         LOD_ExternVColorEditor &color_editor,
00100         LOD_ExternBufferEditor &extern_editor
00101 ) :
00102         m_mesh(mesh),
00103         m_face_editor(face_editor),
00104         m_color_editor(color_editor),
00105         m_extern_editor(extern_editor),
00106         m_is_armed (false)
00107 {       
00108         m_deg_edges.reserve(32);
00109         m_deg_faces.reserve(32);
00110         m_deg_vertices.reserve(32);
00111         m_update_faces.reserve(32);
00112         m_new_edges.reserve(32);
00113         m_update_vertices.reserve(32);
00114 };
00115 
00116         bool
00117 LOD_NdQSDecimator::
00118 CollapseEdge(
00119 ){
00120         
00121         // find an edge to collapse
00122         
00123         // FIXME force an edge collapse
00124         // or return false
00125 
00126         vector<LOD_Edge> & edges = m_mesh.EdgeSet();
00127         vector<LOD_Vertex> & verts = m_mesh.VertexSet();
00128         vector<LOD_NdQuadric> & quadrics = m_quadric_editor->Quadrics();
00129         int size = edges.size();
00130 
00131         if (size == 0) return false;
00132 
00133         const int heap_top = m_heap->Top();
00134 
00135         if (heap_top == -1 || edges[heap_top].HeapKey() <= -MT_INFINITY) {
00136                 return false;
00137         }
00138         
00139         // compute the target position
00140 
00141         TNT::Vector<MT_Scalar> new_vector(6,MT_Scalar(0)); 
00142 
00143         m_quadric_editor->TargetVertex(edges[heap_top],new_vector,m_color_editor);
00144 
00145 
00146         MT_Vector3 new_vertex(
00147                 new_vector[0],
00148                 new_vector[1],
00149                 new_vector[2]
00150         );
00151         for (int i = 3; i < 6;i++) {
00152                 if (new_vector[i] > MT_Scalar(1)) {
00153                         new_vector[i] = MT_Scalar(1);
00154                 } else 
00155                 if (new_vector[i] < MT_Scalar(0)) {
00156                         new_vector[i] = MT_Scalar(0);
00157                 }
00158         }
00159         MT_Vector3 new_color(
00160                 new_vector[3],
00161                 new_vector[4],
00162                 new_vector[5]
00163         );
00164 
00165         // bounds check?
00166 
00167                 
00168         LOD_NdQuadric & q0 = quadrics[edges[heap_top].m_verts[0]];
00169         LOD_NdQuadric & q1 = quadrics[edges[heap_top].m_verts[1]];
00170 
00171         const LOD_VertexInd v0ind = edges[heap_top].m_verts[0];
00172         const LOD_VertexInd v1ind = edges[heap_top].m_verts[1];
00173 
00174         LOD_Vertex &v0 = verts[v0ind];
00175         LOD_Vertex &v1 = verts[v1ind];
00176 
00177         LOD_NdQuadric sum = q0;
00178         sum += q1;
00179 
00180 
00181         if (m_collapser->CollapseEdge(
00182                         heap_top,
00183                         m_mesh,
00184                         m_deg_edges,
00185                         m_deg_faces,
00186                         m_deg_vertices,
00187                         m_new_edges,
00188                         m_update_faces,
00189                         m_update_vertices
00190         )) {
00191 
00192                 // assign new vertex position
00193 
00194                 v0.pos = new_vertex;
00195                 v1.pos = new_vertex;
00196 
00197                 // assign the new vertex color
00198                         
00199                 m_color_editor.SetColor(new_color,v0ind);
00200                 m_color_editor.SetColor(new_color,v1ind);
00201 
00202                 // sum the quadrics of v0 and v1
00203                 q0 = sum;
00204                 q1 = sum;
00205 
00206                 // ok update the primitive properties
00207 
00208                 m_face_editor.Update(m_update_faces);   
00209                 m_face_editor.UpdateVertexNormals(m_update_vertices);
00210 
00211                 // update the external vertex buffer 
00212                 m_extern_editor.CopyModifiedVerts(m_mesh,m_update_vertices);
00213 
00214                 // update the external face buffer
00215                 m_extern_editor.CopyModifiedFaces(m_mesh,m_update_faces);
00216 
00217                 // update the edge heap
00218                 UpdateHeap(m_deg_edges,m_new_edges);
00219 
00220                 m_quadric_editor->Remove(m_deg_vertices);
00221                 m_face_editor.Remove(m_deg_faces);
00222                 m_face_editor.RemoveVertexNormals(m_deg_vertices);              
00223                 m_color_editor.RemoveVertexColors(m_deg_vertices);
00224                                 
00225                 // delete the primitives
00226 
00227                 DeletePrimitives(m_deg_edges,m_deg_faces,m_deg_vertices);
00228 
00229         } else {
00230                 // the edge could not be collapsed at the moment - so
00231                 // we adjust it's priority and add it back to the heap.
00232                 m_heap->Remove(edges.begin(),0);
00233                 edges[heap_top].HeapKey() = - MT_INFINITY;
00234                 m_heap->Insert(edges.begin(),heap_top);
00235         }
00236 
00237         //clear all the temporary buffers
00238 
00239         m_deg_faces.clear();
00240         m_deg_edges.clear();
00241         m_deg_vertices.clear();
00242         
00243         m_update_faces.clear();
00244         m_update_vertices.clear();
00245         m_new_edges.clear();
00246 
00247         return true;
00248 
00249 }       
00250 
00251         void
00252 LOD_NdQSDecimator::
00253 DeletePrimitives(
00254         const vector<LOD_EdgeInd> & degenerate_edges,
00255         const vector<LOD_FaceInd> & degenerate_faces,
00256         const vector<LOD_VertexInd> & degenerate_vertices
00257 ) {
00258 
00259         // assumes that the 3 vectors are sorted in descending order.
00260 
00261         // Delete Degnerate primitives
00263 
00264 
00265         // delete the old edges - we have to be very careful here
00266         // mesh.delete() swaps edges to be deleted with the last edge in 
00267         // the edge buffer. However the next edge to be deleted may have
00268         // been the last edge in the buffer!
00269 
00270         // One way to solve this is to sort degenerate_edges in descending order.
00271         // And then delete them in that order.
00272         
00273         // it is also vital that degenerate_edges contains no duplicates
00274 
00275         vector<LOD_EdgeInd>::const_iterator edge_it = degenerate_edges.begin();
00276         vector<LOD_EdgeInd>::const_iterator edge_end = degenerate_edges.end();
00277 
00278         for (; edge_it != edge_end; ++edge_it) {
00279                 m_mesh.DeleteEdge(*edge_it,m_heap);
00280         }
00281 
00282 
00283 
00284         vector<LOD_FaceInd>::const_iterator face_it = degenerate_faces.begin();
00285         vector<LOD_FaceInd>::const_iterator face_end = degenerate_faces.end();
00286         
00287         for (;face_it != face_end; ++face_it) {
00288                 m_mesh.DeleteFace(m_extern_editor,*face_it);
00289         }
00290 
00291         vector<LOD_VertexInd>::const_iterator vertex_it = degenerate_vertices.begin();
00292         vector<LOD_VertexInd>::const_iterator vertex_end = degenerate_vertices.end();
00293         
00294         for (;vertex_it != vertex_end; ++vertex_it) {
00295                 m_mesh.DeleteVertex(m_extern_editor,*vertex_it);
00296         }
00297 }
00298 
00299 
00300         bool
00301 LOD_NdQSDecimator::
00302 BuildHeap(
00303 ){
00304         // build the geometric quadrics 
00305 
00306         if (m_quadric_editor->BuildQuadrics(m_face_editor,true) == false) return false;
00307 
00308         // add in the property quadrics.
00309         ComputePropertyQuadrics();
00310 
00311         m_quadric_editor->InitializeHeapKeys(m_color_editor);
00312 
00313         m_heap = Heap<LOD_Edge>::New();
00314         // load in edge pointers to the heap
00315 
00316         vector<LOD_Edge> & edge_set= m_mesh.EdgeSet();
00317         vector<LOD_Edge>::const_iterator edge_end = edge_set.end();
00318         vector<LOD_Edge>::iterator edge_start = edge_set.begin();
00319 
00320         vector<int> & heap_vector = m_heap->HeapVector();
00321 
00322         for (int i = 0; i < edge_set.size(); ++i) {
00323                 edge_set[i].HeapPos() = i;
00324                 heap_vector.push_back(i);
00325         }
00326         
00327         m_heap->MakeHeap(edge_set.begin());
00328 
00329         return true;
00330 }
00331 
00332         void
00333 LOD_NdQSDecimator::
00334 UpdateHeap(
00335         vector<LOD_EdgeInd> &deg_edges,
00336         vector<LOD_EdgeInd> &new_edges
00337 ){
00338         // first of all compute values for the new edges 
00339         // and bung them on the heap.
00340 
00341         vector<LOD_Edge>  & edge_set= m_mesh.EdgeSet();
00342 
00343         vector<LOD_EdgeInd>::const_iterator edge_it = new_edges.begin();
00344         vector<LOD_EdgeInd>::const_iterator end_it = new_edges.end();
00345 
00346 
00347         // insert all the new edges             
00349 
00350         // compute edge costs ffor the new edges
00351 
00352         m_quadric_editor->ComputeEdgeCosts(new_edges,m_color_editor);
00353 
00354         // inser the new elements into the heap
00355 
00356         for (; edge_it != end_it; ++edge_it) {          
00357                 m_heap->Insert(edge_set.begin(),*edge_it);
00358         }
00359 
00360 
00361         // remove all the old values from the heap
00362 
00363         edge_it = deg_edges.begin();
00364         end_it = deg_edges.end();
00365 
00366         for (; edge_it != end_it; ++edge_it) {
00367                 LOD_Edge &e = edge_set[*edge_it];
00368                 m_heap->Remove(edge_set.begin(),e.HeapPos());
00369 
00370                 e.HeapPos() = 0xffffffff;
00371 
00372         }
00373 }
00374         
00375         void
00376 LOD_NdQSDecimator::
00377 ComputePropertyQuadrics(
00378 ){
00379 
00380         vector<LOD_TriFace> & faces = m_mesh.FaceSet();
00381         vector<LOD_Vertex> & verts = m_mesh.VertexSet();
00382         vector<LOD_NdQuadric> & quadrics = m_quadric_editor->Quadrics();
00383         const vector<MT_Vector3> &face_normals = m_face_editor.Normals();
00384 
00385         // compute the linear functionals for each face
00386 
00387         // For each property associated with that face we compute
00388         // a property gradient, construct a quadric based on this and add
00389         // it to each of the face's vertex quadrics.
00390 
00391         vector<LOD_TriFace>::const_iterator f_start = faces.begin();
00392         vector<LOD_TriFace>::const_iterator f_end = faces.end();
00393         vector<LOD_TriFace>::iterator f = faces.begin();
00394 
00395         // we need a little matrix space to help us with the
00396         // linear functional computation.
00397 
00398         TNT::Matrix<MT_Scalar> mat(4,4,MT_Scalar(0));
00399         TNT::Vector<MT_Scalar> vec(4,MT_Scalar(1));
00400 
00401         // some pivots.
00402 
00403         TNT::Vector<TNT::Subscript> pivots(4,int(0));
00404 
00405         // Quadrics now consume heap memory so let's
00406         // reuse one in the following loop rather than 
00407         // making one each iteration.
00408 
00409         LOD_NdQuadric qp;
00410 
00411 
00412         for (;f != f_end; ++f) {
00413                 
00414                 // collect the coordinates of the face
00415                 // and the normal into a matrix
00416         
00417                 const LOD_VertexInd * f_verts= f->m_verts;
00418 
00419                 const MT_Vector3 & p0 = verts[f_verts[0]].pos;
00420                 const MT_Vector3 & p1 = verts[f_verts[1]].pos;
00421                 const MT_Vector3 & p2 = verts[f_verts[2]].pos;
00422         
00423                 const MT_Vector3 c0 = m_color_editor.IndexColor(f_verts[0]);
00424                 const MT_Vector3 c1 = m_color_editor.IndexColor(f_verts[1]);
00425                 const MT_Vector3 c2 = m_color_editor.IndexColor(f_verts[2]);
00426 
00427                 // get the face normal  
00428 
00429                 const MT_Vector3 & fn = face_normals[int(f - f_start)];
00430 
00431                 // load into mat
00432 
00433                 int i;
00434                 for (i = 0; i < 3; i++) {
00435                         mat[0][i] = p0[i];
00436                         mat[1][i] = p1[i];
00437                         mat[2][i] = p2[i];
00438                         mat[3][i] = fn[i];
00439                 }
00440                 mat[0][3] = MT_Scalar(1);
00441                 mat[1][3] = MT_Scalar(1);
00442                 mat[2][3] = MT_Scalar(1);
00443                 mat[3][3] = MT_Scalar(0);
00444 
00445                 // Compute the pivots
00446 
00447                 if (TNT::LU_factor(mat,pivots)) {
00448                         // bad face!
00449                         continue;
00450                 }       
00451 
00452                 // compute red linear functional
00453 
00454                 vec[0] = c0[0];                         
00455                 vec[1] = c1[0];
00456                 vec[2] = c2[0];
00457                 vec[3] = MT_Scalar(0);
00458 
00459                 TNT::LU_solve(mat,pivots,vec);
00460 
00461                 // construct a quadric based on this functional
00462 
00463                 qp = LOD_NdQuadric(
00464                         MT_Vector3(vec[0],vec[1],vec[2]),
00465                         vec[3],
00466                         0
00467                 );                      
00468                 // compute green functional
00469 
00470                 vec[0] = c0[1];                         
00471                 vec[1] = c1[1];
00472                 vec[2] = c2[1];
00473                 vec[3] = MT_Scalar(0);
00474 
00475                 TNT::LU_solve(mat,pivots,vec);
00476 
00477                 // construct a quadric based on this functional
00478 
00479                 qp += LOD_NdQuadric(
00480                         MT_Vector3(vec[0],vec[1],vec[2]),
00481                         vec[3],
00482                         1
00483                 );                      
00484                 
00485                 // compute blue functional
00486 
00487                 vec[0] = c0[2];                         
00488                 vec[1] = c1[2];
00489                 vec[2] = c2[2];
00490                 vec[3] = MT_Scalar(0);
00491 
00492                 TNT::LU_solve(mat,pivots,vec);
00493 
00494                 // construct a quadric based on this functional
00495 
00496                 qp += LOD_NdQuadric(
00497                         MT_Vector3(vec[0],vec[1],vec[2]),
00498                         vec[3],
00499                         2
00500                 );                      
00501         
00502                 // add to the geometric quadrics of each of the 
00503                 // vertices of f
00504                 
00505                 qp *= MT_Scalar(50);    
00506 
00507 
00508                 quadrics[f_verts[0]] += qp;
00509                 quadrics[f_verts[1]] += qp;
00510                 quadrics[f_verts[2]] += qp;
00511         
00512                 qp.Clear();
00513 
00514         }
00515 }
00516 
00517 
00518