Blender V2.61 - r43446

LOD_NdQSDecimator.cpp

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