Blender V2.61 - r43446

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