|
Blender
V2.59
|
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 }