Blender  V2.59
LOD_EdgeCollapser.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: LOD_EdgeCollapser.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_EdgeCollapser.h"
00035 
00036 #include "LOD_ManMesh2.h"
00037 #include "CTR_TaggedSetOps.h"
00038 #include <algorithm>
00039 #include <functional>
00040 
00041 
00042 using namespace std;
00043 
00044 
00045         LOD_EdgeCollapser * 
00046 LOD_EdgeCollapser::
00047 New(
00048 ){
00049         return new LOD_EdgeCollapser();
00050 }
00051 
00052 
00053         bool
00054 LOD_EdgeCollapser::
00055 TJunctionTest(
00056         LOD_ManMesh2 &mesh,
00057         vector<LOD_EdgeInd> &e_v0v1,
00058         LOD_EdgeInd collapse_edge
00059 ){
00060 
00061         // we need to copy the egdes in e_v0v1 from the mesh
00062         // into a new buffer -> we are going to modify them
00063 
00064         int original_size = e_v0v1.size();
00065         if (original_size == 0) return true;
00066 
00067         vector<LOD_Edge> &edge_set = mesh.EdgeSet();
00068 
00069         LOD_VertexInd c_v0 = edge_set[collapse_edge].m_verts[0];
00070         LOD_VertexInd c_v1 = edge_set[collapse_edge].m_verts[1];
00071 
00072         vector<LOD_Edge> temp_edges;
00073         temp_edges.reserve(e_v0v1.size());
00074 
00075         vector<LOD_EdgeInd>::iterator edge_it = e_v0v1.begin();
00076         vector<LOD_EdgeInd>::const_iterator edge_end = e_v0v1.end();
00077 
00078         for (;edge_it != edge_end; ++edge_it) {
00079                 temp_edges.push_back(edge_set[*edge_it]);
00080         }
00081 
00082         // in the copied edges replace all instances of c_v0 with c_v1
00083 
00084         vector<LOD_Edge>::iterator e_it = temp_edges.begin();
00085         vector<LOD_Edge>::const_iterator e_it_end = temp_edges.end();
00086                 
00087         for (; e_it != e_it_end; ++e_it) {
00088 
00089                 if (e_it->m_verts[0] == c_v0) {
00090                         e_it->m_verts[0] = c_v1;
00091                 }
00092                 if (e_it->m_verts[1] == c_v0) {
00093                         e_it->m_verts[1] = c_v1;
00094                 }
00095 
00096                 // normalize the edge
00097                 if (int(e_it->m_verts[0]) > int(e_it->m_verts[1])) {
00098                         LOD_EdgeInd temp = e_it->m_verts[0];
00099                         e_it->m_verts[0] = e_it->m_verts[1];
00100                         e_it->m_verts[1] = temp;
00101                 }
00102         }
00103 
00104         // sort the edges using the edge less functional 
00105 
00106         sort(temp_edges.begin(),temp_edges.end(),LOD_EdgeCollapser::less());
00107         // count the unique edges.
00108 
00109         e_it = temp_edges.begin();
00110         e_it_end = temp_edges.end();
00111         
00112         int coincedent_edges = 0;
00113 
00114         vector<LOD_Edge>::const_iterator last_edge = e_it;
00115         ++e_it;
00116                 
00117         for (; e_it != e_it_end; ++e_it) {
00118         
00119                 if ((e_it->m_verts[0] == last_edge->m_verts[0]) &&
00120                         (e_it->m_verts[1] == last_edge->m_verts[1])
00121                 ) {
00122                         ++coincedent_edges;
00123                 }
00124                 last_edge = e_it;
00125         }
00126 
00127         // now if the collapse edge is a boundary edges 
00128         // then we are alloved at most one coincedent edge
00129 
00130         // otherwise at most 2 coincedent edges
00131 
00132         if (edge_set[collapse_edge].BoundaryEdge()) {
00133                 return (coincedent_edges > 1);
00134         } else {
00135                 return (coincedent_edges > 2);
00136         }
00137 
00138 
00139 }
00140 
00141 
00142         
00143         bool
00144 LOD_EdgeCollapser::
00145 CollapseEdge(
00146         LOD_EdgeInd ei,
00147         LOD_ManMesh2 &mesh,
00148         vector<LOD_EdgeInd> & degenerate_edges,
00149         vector<LOD_FaceInd> & degenerate_faces,
00150         vector<LOD_VertexInd> & degenerate_vertices,
00151         vector<LOD_EdgeInd> & new_edges,
00152         vector<LOD_FaceInd> & update_faces,
00153         vector<LOD_VertexInd> & update_vertices
00154 ){
00155 
00156         vector<LOD_Vertex>      &verts = mesh.VertexSet();
00157         vector<LOD_Edge>        &edges = mesh.EdgeSet();
00158         vector<LOD_TriFace> &faces = mesh.FaceSet();
00159 
00160         // shouldn't do this (use mesh interface instead!)
00161         LOD_VertexInd v0_ind = edges[ei].m_verts[0];
00162         LOD_VertexInd v1_ind = edges[ei].m_verts[1];
00163 #if 0
00164         LOD_Vertex &v0 = verts[v0_ind];
00165         LOD_Vertex &v1 = verts[v1_ind];
00166 #endif
00167         vector<vector<LOD_EdgeInd> > e_v01(2);
00168         e_v01[0].reserve(32);
00169         e_v01[1].reserve(32);
00170         
00171         mesh.VertexEdges(v0_ind,e_v01[0]);
00172         mesh.VertexEdges(v1_ind,e_v01[1]);
00173 
00174 
00175         // compute the union of e_v0 and e_v1 -> this is the degenerate edges of the collapse
00176         // we remove old edges and replace edges inside the collapse zone with new ones 
00177 
00178         CTR_TaggedSetOps<LOD_EdgeInd,LOD_Edge>::Union(e_v01,edges,degenerate_edges);
00179 
00180         vector< vector<LOD_FaceInd> > p_v01(2);
00181         p_v01[0].reserve(32);
00182         p_v01[1].reserve(32);
00183 
00184         mesh.VertexFaces(v0_ind,p_v01[0]);
00185         mesh.VertexFaces(v1_ind,p_v01[1]);
00186 
00187         // compute the union of p_v0 anf p_v1
00188         vector<LOD_FaceInd> p_v0v1;
00189         p_v0v1.reserve(32);
00190 
00191         CTR_TaggedSetOps<LOD_FaceInd,LOD_TriFace>::Union(p_v01,faces,p_v0v1);
00192 
00193         // compute the union of all the edges in p_v0v1 this is the collapse zone
00194 
00195         vector<vector<LOD_EdgeInd> > e_input_vectors(p_v0v1.size());
00196 
00197         vector<LOD_FaceInd>::iterator p_v0v1_end = p_v0v1.end();
00198         vector<LOD_FaceInd>::iterator p_v0v1_start = p_v0v1.begin();
00199 
00200         vector<vector<LOD_FaceInd> >::iterator vector_insert_it = e_input_vectors.begin();
00201         
00202         for (;p_v0v1_start != p_v0v1_end; ++p_v0v1_start , ++vector_insert_it) {
00203                 mesh.FaceEdges(*p_v0v1_start,*vector_insert_it);
00204         }
00205 
00206         vector<LOD_EdgeInd> collapse_zone;
00207         collapse_zone.reserve(32);
00208 
00209         CTR_TaggedSetOps<LOD_EdgeInd,LOD_Edge>::Union(e_input_vectors,edges,collapse_zone);
00210 
00211         // compute the ring edges = collpase_zone - e_v0v1
00212 
00213         vector<LOD_EdgeInd> edge_ring;
00214         edge_ring.reserve(32);
00215 
00216         CTR_TaggedSetOps<LOD_EdgeInd,LOD_Edge>::Difference(collapse_zone,degenerate_edges,edges,edge_ring);
00217 
00218         // T Junction test
00220         // At this point we check to see if any of the polygons
00221         // in p_v0v1 are coninceddent - this leads
00222         // to errors later on if we try and insert a polygon
00223         // into the mesh to an edge which already has 2 polygons.
00224 
00225         // not that t junctions occur naturally from edge collapses
00226         // and are not just the result of coincedent polygons
00227         // for example consider collapsing an edge that forms part
00228         // of a triangular bottle neck.
00229 
00230         // Really we need to make sure that we don't create t-junctions.
00231 
00232         // I think that a sufficient test is to check the number of
00233         // coincedent edge pairs after a collapse. If it is more than 2
00234         // then collapsing the edge may result in an undeleted edge 
00235         // sharing more than 2 polygons. This test probably is too 
00236         // restictive though.
00237         
00238         // To perform this test we need to make a copy of the edges
00239         // in e_v0v1. We then apply the contraction to these edge
00240         // copies. Sort them using a function that places coincedent 
00241         // edges next to each other. And then count the number
00242         // of coincedent pairs. 
00243 
00244         // Of course we have to do this test before we change any of the
00245         // mesh -> so we can back out safely.
00246 
00247         if (TJunctionTest(mesh,degenerate_edges,ei)) return false; 
00248 
00249         // Compute the set of possibly degenerate vertices
00250         // this is the union of all the vertices of polygons
00251         // of v0 and v1
00252 
00253         vector<LOD_FaceInd>::iterator face_it = p_v0v1.begin();
00254         vector<LOD_FaceInd>::const_iterator face_end = p_v0v1.end();
00255 
00256 
00257         vector<vector<LOD_VertexInd> > p_v0v1_vertices(p_v0v1.size());
00258         
00259         for (int i = 0; face_it != face_end; ++face_it, ++i) {
00260                 mesh.FaceVertices(*face_it,p_v0v1_vertices[i]);
00261         }
00262         
00263         vector<LOD_VertexInd> vertex_ring;
00264         vertex_ring.reserve(32);
00265 
00266         CTR_TaggedSetOps<LOD_VertexInd,LOD_Vertex>::Union(p_v0v1_vertices,verts,vertex_ring);
00267 
00268         // remove all the internal edges e_v0v1 from the mesh.
00269         // for each edge remove the egde from it's vertices edge lists.
00270 
00271         vector<LOD_EdgeInd>::iterator edge_it = degenerate_edges.begin();
00272         vector<LOD_EdgeInd>::const_iterator edge_end = degenerate_edges.end();
00273 
00274         for (; !(edge_it == edge_end); ++edge_it) {
00275                         
00276                 LOD_EdgeInd ed = (*edge_it);
00277                 LOD_Edge & edge = edges[ed];//*edge_it];
00278         
00279                 verts[edge.m_verts[0]].RemoveEdge(ed);
00280                 verts[edge.m_verts[1]].RemoveEdge(ed);
00281         }
00282 
00283         // we postpone deletion of the internal edges untill the end
00284         // this is because deleting edges invalidates all of the 
00285         // EdgeInd vectors above.
00286 
00287                 
00288         // now untie all the polygons in p_v0v1 from the edge ring
00289 
00290         // select all polygons in p_v0v1
00291 
00292         face_it = p_v0v1.begin();
00293         face_end = p_v0v1.end();
00294 
00295         for (;face_it != face_end; ++face_it) {
00296                 faces[*face_it].SetSelectTag(true);
00297         }
00298 
00299         edge_it = edge_ring.begin();
00300         edge_end = edge_ring.end();
00301 
00302         for (;edge_it != edge_end; ++edge_it) {
00303                 LOD_Edge & edge = edges[*edge_it];
00304 
00305                 // presumably all edges in edge_ring point to at least
00306                 // one polygon from p_v0v1
00307                 
00308                 if (!edge.m_faces[0].IsEmpty() && faces[edge.m_faces[0]].SelectTag()) {
00309                         edge.m_faces[0].Invalidate();
00310                 }
00311 
00312                 if (!edge.m_faces[1].IsEmpty() && faces[edge.m_faces[1]].SelectTag()) {
00313                         edge.m_faces[1].Invalidate();
00314                 }
00315         }
00316         
00317         // deselect the faces
00318 
00319         face_it = p_v0v1.begin();
00320         face_end = p_v0v1.end();
00321 
00322         for (;face_it != face_end; ++face_it) {
00323                 faces[*face_it].SetSelectTag(false);
00324         }
00325 
00326         // perform the edge collapse
00328 
00329         // iterate through the polygons of p_v0 and replace the vertex
00330         // index v0 with v1
00331 
00332         face_it = p_v01[0].begin();
00333         face_end = p_v01[0].end();
00334         
00335         for (;face_it != face_end; ++face_it) {
00336                 faces[*face_it].SwapVertex(v0_ind,v1_ind);
00337         }
00338 
00339         face_it = p_v0v1.begin();
00340         face_end = p_v0v1.end();
00341         
00342         for (;face_it != face_end; ++face_it) {
00343                 if (faces[*face_it].Degenerate()) {
00344                         degenerate_faces.push_back(*face_it);
00345                 } else {
00346                         update_faces.push_back(*face_it);
00347                 }
00348         }
00349         
00350         // Add all the non-degenerate faces back into the 
00351         // mesh. Get a record of the new edges created in
00352         // this process.
00353 
00354         face_it = update_faces.begin();
00355         face_end = update_faces.end();
00356 
00357         for (;face_it != face_end; ++face_it) {
00358                 mesh.ConnectTriangle(*face_it,new_edges);
00359         }
00360 
00361         // degenerate ring primitives
00363 
00364         // we now need to examine each of the edges on the ring
00365         // and work out if they are degenerate - if so we attempt
00366         // to delete them -> add them to the other edges to delete
00367         // in e_v0v1
00368 
00369         edge_it = edge_ring.begin();
00370         edge_end = edge_ring.end();
00371 
00372         for (;edge_it != edge_end; ++edge_it) {
00373                 if (edges[*edge_it].Degenerate()) {
00374                         degenerate_edges.push_back(*edge_it);
00375                 }
00376         }
00377 
00378         // do the same for the ring vertices.
00379                 
00380         vector<LOD_VertexInd>::iterator vertex_it = vertex_ring.begin();
00381         vector<LOD_VertexInd>::const_iterator vertex_end = vertex_ring.end();
00382 
00383         for (;vertex_it != vertex_end; ++vertex_it) {
00384                 if (verts[*vertex_it].Degenerate()) {
00385                         degenerate_vertices.push_back(*vertex_it);
00386                 } else {
00387                         update_vertices.push_back(*vertex_it);
00388                 }
00389         }
00390 
00391         // we now know all the degenerate primitives
00392         // and the new primitives we have inserted into the mesh
00393 
00394         // We now delete the mesh primitives, mesh.DeleteXXXXXX() methods
00395         // assume that the index vectors are sorted into descending order.
00396         // we do that now.
00397 
00398         sort(degenerate_edges.begin(),degenerate_edges.end(),LOD_EdgeInd::greater());
00399         sort(degenerate_faces.begin(),degenerate_faces.end(),LOD_FaceInd::greater());
00400         sort(degenerate_vertices.begin(),degenerate_vertices.end(),LOD_VertexInd::greater());
00401 
00402         
00403         return true;
00404         
00405 }
00406 
00407 LOD_EdgeCollapser::
00408 LOD_EdgeCollapser(
00409 ){
00410         // nothing to do
00411 }