00001
00002
00003
00004
00005
00006
00007
00008 #include "../common/standard.h"
00009 #include "Matrix.h"
00010
00011 #include "QEM_Quadric.h"
00012 #include "QEM_ProgMesh.h"
00013
00014
00015 using namespace QEM;
00016
00017 void ProgMesh::recalculateCosts()
00018 {
00019 int nFaces = faces.size();
00020
00021
00022 for (int i = 0; i < nFaces; i++)
00023 {
00024 Face &f = faces[i];
00025 f.assertValid(i);
00026 Quadric q = f.calculateQuadric(i, vertices);
00027
00028
00029 f.getVertex(0, vertices, i).quadric += q;
00030 f.getVertex(1, vertices, i).quadric += q;
00031 f.getVertex(2, vertices, i).quadric += q;
00032
00033 if (i%40 == 0)
00034 {
00035
00036 }
00037 }
00038
00039
00040
00041 for (EdgePtr iter = edges.begin(); iter != edges.end(); iter++)
00042 {
00043 Edge &e = *iter;
00044
00045 VertexQuadric v1 = vertices[e.getV1()];
00046 VertexQuadric v2 = vertices[e.getV2()];
00047
00048
00049 Quadric sum = v1.quadric + v2.quadric;
00050
00051
00052
00053 Vertex v;
00054 if (!sum.getOptimumPoint (v))
00055 v = (v1 + v2) / 2.;
00056
00057 e.setCachedCost(sum.getCost(v));
00058 }
00059
00060
00061
00062
00063 edges.sort(&vertices);
00064
00065
00066
00067 }
00068
00069 EdgePtr ProgMesh::addEdge (int faceIndex, int whichEdge, int vertexIndex1, int vertexIndex2)
00070 {
00071 VertexPairEdgeMap::iterator i;
00072 i = vertexPairEdgeMap.find (VertexPair (vertexIndex2, vertexIndex1));
00073
00074
00075 if (i != vertexPairEdgeMap.end())
00076 {
00077 int index = (*i).second;
00078 Face &f = faces[index/3];
00079 Edge &e = f.getEdge(index%3);
00080 e.setFace2(faceIndex,whichEdge);
00081
00082 vertexPairEdgeMap.erase (i);
00083
00084 return faces[index/3].getEdgePtr(index%3);
00085 }
00086 else
00087 {
00088 Edge newEdge(faceIndex, whichEdge, vertexIndex1, vertexIndex2);
00089 edges.push_front (newEdge);
00090 vertexPairEdgeMap[VertexPair(vertexIndex1,vertexIndex2)] = newEdge.edgeIndexFirst();
00091 return edges.begin();
00092 }
00093 }
00094
00095 std::pair<int, int> findCommon(int a, int b, int c, int d)
00096 {
00097 int af = a/3;
00098 int bf = b/3;
00099 int cf = c/3;
00100 int df = d/3;
00101
00102
00103 if (a == b || c == d)
00104 {
00105 throw "findCommon(): degeneracy occurred. No further collapses allowed. (1)";
00106 }
00107 if (af == bf || cf == df)
00108 {
00109 throw "findCommon(): degeneracy occurred. No further collapses allowed. (2)";
00110 }
00111
00112 if (af == cf)
00113 a = d;
00114 else if (af == df)
00115 a = c;
00116 else if (bf == cf)
00117 b = d;
00118 else if (bf == df)
00119 b = c;
00120 else
00121 {
00122 throw "findCommon(): degeneracy occurred. No further collapses allowed.";
00123 }
00124
00125 std::pair<int,int> rtn(a,b);
00126 rtn.first = a;
00127 rtn.second = b;
00128
00129 return rtn;
00130 }
00131
00132 bool ProgMesh::willDegenerate (EdgePtr e1, EdgePtr e2) const
00133 {
00134 Edge &edge1 = *e1;
00135 Edge &edge2 = *e2;
00136
00137
00138
00139 if (edge1.isBorder() || edge2.isBorder())
00140 return false;
00141
00142 std::pair<int,int> p = findCommon(
00143 edge1.edgeIndexFirst(),
00144 edge1.edgeIndexSecond(),
00145 edge2.edgeIndexFirst(),
00146 edge2.edgeIndexSecond());
00147
00148 int firstIndex = p.first/3;
00149 int secondIndex = p.second/3;
00150
00151 int v1, v2, v3, v4, v5, v6;
00152 v1 = faces[firstIndex].getVertexIndex(0, firstIndex);
00153 v2 = faces[firstIndex].getVertexIndex(1, firstIndex);
00154 v3 = faces[firstIndex].getVertexIndex(2, firstIndex);
00155 v4 = faces[secondIndex].getVertexIndex(0, secondIndex);
00156 v5 = faces[secondIndex].getVertexIndex(1, secondIndex);
00157 v6 = faces[secondIndex].getVertexIndex(2, secondIndex);
00158
00159 int n = 0;
00160 if (v1 == v4 || v1 == v5 || v1 == v6) n++;
00161 if (v2 == v4 || v2 == v5 || v2 == v6) n++;
00162 if (v3 == v4 || v3 == v5 || v3 == v6) n++;
00163
00164 if (n > 1)
00165 return true;
00166 return false;
00167 }
00168
00169
00170 EdgePtr ProgMesh::consolidateEdges (EdgePtr e1, EdgePtr e2, int deadFaceIndex)
00171 {
00172 Edge &edge1 = *e1;
00173 Edge &edge2 = *e2;
00174
00175 if (!edge1.isBorder() &&
00176 edge1.edgeIndexFirst()/3 == edge1.edgeIndexSecond()/3)
00177 {
00178 return edges.end();
00179 }
00180
00181 if (!edge2.isBorder() &&
00182 edge2.edgeIndexFirst()/3 == edge2.edgeIndexSecond()/3)
00183 {
00184 return edges.end();
00185 }
00186
00187
00188
00189
00190 if (!edge1.isBorder() && !edge2.isBorder())
00191 {
00192
00193
00194
00195
00196 std::pair<int,int> p = findCommon(
00197 edge1.edgeIndexFirst(),
00198 edge1.edgeIndexSecond(),
00199 edge2.edgeIndexFirst(),
00200 edge2.edgeIndexSecond());
00201
00202
00203 #if 0
00204 int v1, v2, v3, v4, v5, v6;
00205 int firstIndex = p.first/3;
00206 int secondIndex = p.second/3;
00207 v1 = faces[firstIndex].getVertexIndex(0, firstIndex);
00208 v2 = faces[firstIndex].getVertexIndex(1, firstIndex);
00209 v3 = faces[firstIndex].getVertexIndex(2, firstIndex);
00210 v4 = faces[secondIndex].getVertexIndex(0, secondIndex);
00211 v5 = faces[secondIndex].getVertexIndex(1, secondIndex);
00212 v6 = faces[secondIndex].getVertexIndex(2, secondIndex);
00213
00214 int n = 0;
00215 if (v1 == v4 || v1 == v5 || v1 == v6) n++;
00216 if (v2 == v4 || v2 == v5 || v2 == v6) n++;
00217 if (v3 == v4 || v3 == v5 || v3 == v6) n++;
00218 #endif
00219
00220 edge1.setFace1 (p.first/3, p.first%3);
00221 edge1.setFace2 (p.second/3, p.second%3);
00222
00223 faces[p.first/3].setEdge(p.first%3, e1);
00224 faces[p.second/3].setEdge(p.second%3,e1);
00225
00226 edges.erase (e2);
00227 return e1;
00228
00229 }
00230
00231
00232 if (edge1.isBorder() && edge2.isBorder())
00233 {
00234 edges.erase (e1);
00235 edges.erase (e2);
00236 return edges.end();
00237 }
00238
00239 if (edge1.isBorder())
00240 {
00241 return consolidateEdges (e2, e1, deadFaceIndex);
00242 }
00243
00244 assert (!edge1.isBorder());
00245 assert (edge1.hasFirstNeighbor());
00246
00247
00248
00249
00250 if (edge2.isBorder())
00251 {
00252
00253 edges.erase (e2);
00254
00255
00256
00257 if (edge1.faceIndexFirst() == deadFaceIndex)
00258 {
00259 assert (edge1.faceIndexSecond() != deadFaceIndex);
00260
00261
00262 edge1.removeFace1();
00263 }
00264 else if (edge1.faceIndexSecond() == deadFaceIndex)
00265 {
00266 assert (edge1.faceIndexFirst() != deadFaceIndex);
00267
00268
00269 edge1.removeFace2();
00270 }
00271 else
00272 assert(!"ProgMesh::consolidateEdges(): one of the edges passed in isn't attached to a dead face");
00273 return e1;
00274 }
00275 else
00276 throw ("ProgMesh::consolidateEdges(): shouldn't ever get here!");
00277
00278 return edges.end();
00279 }
00280
00281
00282
00283 Vertex ProgMesh::getOptimumPointForEdge (Edge &edge)
00284 {
00285 Vertex optimumPoint;
00286 Quadric q =
00287 vertices[edge.getV1()].quadric +
00288 vertices[edge.getV2()].quadric;
00289
00290 if (!q.getOptimumPoint(optimumPoint))
00291 {
00292 VertexQuadric &v1 = vertices[edge.getV1()];
00293 VertexQuadric &v2 = vertices[edge.getV2()];
00294 optimumPoint = (v1 + v2) / 2.;
00295 }
00296 return optimumPoint;
00297 }
00298
00304 void ProgMesh::reportProgress (char *str)
00305 {
00306
00307 }
00308
00309
00310 int ProgMesh::addOptimumPoint(Edge &deadEdge)
00311 {
00312 Vertex optimumPoint = getOptimumPointForEdge (deadEdge);
00313 VertexQuadric v(
00314 optimumPoint[0],
00315 optimumPoint[1],
00316 optimumPoint[2]);
00317
00318 v.quadric = vertices[deadEdge.getV1()].quadric + vertices[deadEdge.getV2()].quadric;
00319
00320 vertices.push_back (v);
00321
00322 int newVertexIndex = vertices.size() - 1;
00323 return newVertexIndex;
00324 }
00325
00326
00327
00328 void ProgMesh::doCollapse(int finalPolygonCount)
00329 {
00330 int n = 0;
00331 int originalPolyCount = getNumFacesTotal();
00332 int numToRemove = originalPolyCount - finalPolygonCount;
00333
00334 reportProgress ("Collapsing...");
00335
00336 while (faces.getNumFacesVisible() > finalPolygonCount)
00337 {
00338 doOneCollapse();
00339
00340 n++;
00341 if (n % 60 == 0)
00342 {
00343 int numRemoved = originalPolyCount - faces.getNumFacesVisible();
00344 float percentRemoved = 100 * (float)numRemoved / numToRemove;
00345
00346 reportProgress (fmtString ("Collapsing %.2lf%% done. %d faces, %d vertices, %d edges",
00347 percentRemoved,
00348 faces.getNumFacesVisible(),
00349 vertices.size(),
00350 edges.size()));
00351
00352 }
00353 }
00354 }
00355
00356
00357
00358 void ProgMesh::doOneCollapse()
00359 {
00360 if (edges.empty())
00361 return;
00362
00363
00364
00365
00366 EdgePtr deadEdgePtr = edges.begin();
00367 Edge &deadEdge = *deadEdgePtr;
00368 int newVertexIndex = addOptimumPoint (deadEdge);
00369
00370 int oldV1 = deadEdge.getV1();
00371 int oldV2 = deadEdge.getV2();
00372
00373 if (oldV1 == oldV2)
00374 MTRACE("warning: collapsing degenerate edge; both vertices have index %d", oldV1);
00375
00376
00377
00378
00379
00380
00381
00382 EdgePair pairsToSew1;
00383 EdgePair pairsToSew2;
00384
00385
00386 if (deadEdge.hasFirstNeighbor())
00387 {
00388
00389 pairsToSew1 = faces[deadEdge.faceIndexFirst()].getOtherTwoEdges (deadEdgePtr);
00390 if (*pairsToSew1.first == *pairsToSew1.second)
00391 {
00392 (*pairsToSew1.first).printDebugString();
00393 (*pairsToSew1.second).printDebugString();
00394 }
00395 assert (pairsToSew1.first != pairsToSew1.second);
00396 assert (faces.faceIsVisible (deadEdge.faceIndexFirst()));
00397 }
00398
00399
00400 if (deadEdge.hasSecondNeighbor())
00401 {
00402 pairsToSew2 = faces[deadEdge.faceIndexSecond()].getOtherTwoEdges (edges.begin());
00403 if (*pairsToSew2.first == *pairsToSew2.second)
00404 {
00405 (*pairsToSew2.first).printDebugString();
00406 (*pairsToSew2.second).printDebugString();
00407 }
00408 assert (pairsToSew2.first != pairsToSew2.second);
00409 assert (faces.faceIsVisible (deadEdge.faceIndexSecond()));
00410 }
00411
00412
00413
00414
00415
00416
00417
00418
00419 if (deadEdge.hasFirstNeighbor())
00420 {
00421 if (willDegenerate(pairsToSew1.first, pairsToSew1.second))
00422 {
00423 deadEdge.setCachedCost (deadEdge.getCachedCost() + 10);
00424 edges.sort (&vertices);
00425 MTRACE("ProgMesh::doOneCollapse(): degeneracy averted\n");
00426 return;
00427 }
00428 }
00429
00430 if (deadEdge.hasSecondNeighbor())
00431 {
00432 if (willDegenerate(pairsToSew2.first, pairsToSew2.second))
00433 {
00434 deadEdge.setCachedCost (deadEdge.getCachedCost() + 10);
00435 edges.sort (&vertices);
00436 MTRACE("ProgMesh::doOneCollapse(): degeneracy averted\n");
00437 return;
00438 }
00439 }
00440
00441
00442
00443
00444
00445
00446
00447
00448 if (deadEdge.hasFirstNeighbor())
00449 faces.swapVertexIndex (oldV1, oldV2, newVertexIndex, deadEdge.faceIndexFirst(), edges);
00450
00451 if (deadEdge.hasSecondNeighbor())
00452 faces.swapVertexIndex (oldV1, oldV2, newVertexIndex, deadEdge.faceIndexSecond(), edges);
00453
00454
00455
00456 if (deadEdge.hasFirstNeighbor())
00457 {
00458 consolidateEdges (pairsToSew1.first, pairsToSew1.second, deadEdge.faceIndexFirst());
00459 }
00460
00461 if (deadEdge.hasSecondNeighbor())
00462 {
00463 consolidateEdges (pairsToSew2.first, pairsToSew2.second, deadEdge.faceIndexSecond());
00464 }
00465
00466 if (deadEdge.hasFirstNeighbor())
00467 {
00468 faces.hideFace (deadEdge.faceIndexFirst());
00469 }
00470
00471 if (deadEdge.hasSecondNeighbor())
00472 {
00473 faces.hideFace (deadEdge.faceIndexSecond());
00474 }
00475
00476
00477 edges.pop_front();
00478
00479
00480
00481
00482 }
00483
00484
00485
00486 void ProgMesh::clear()
00487 {
00488 faces.clear();
00489 edges.clear();
00490 vertices.clear();
00491 vertexPairEdgeMap.clear();
00492 }
00493
00494
00495
00496 void ProgMesh::draw() const
00497 {
00498 int numFaces = faces.size();
00499
00500 for (int i = 0; i < numFaces; i++)
00501 {
00502 if (!faces.faceIsVisible(i))
00503 continue;
00504
00505 faces[i].draw(i, vertices, &colorMap);
00506 }
00507
00508 #if 0 // little ball, to help us see where collapses take place
00509 if (vertices.size() > 0)
00510 {
00511 glPushMatrix();
00512 glTranslatef(
00513 vertices[vertices.size()-1][0],
00514 vertices[vertices.size()-1][1],
00515 vertices[vertices.size()-1][2]);
00516 glutSolidSphere(.01, 20, 20);
00517 glPopMatrix();
00518 }
00519 #endif
00520
00521 }
00522
00523
00524 void ProgMesh::presize (int nTriangles, int nVertices)
00525 {
00526 faces.reserve (nTriangles);
00527 vertices.reserve (nVertices);
00528 }
00529
00530 void ProgMesh::addFace (int v1, int v2, int v3)
00531 {
00532 if (v1 == v2 || v2 == v3 || v1 == v3)
00533 throw RuntimeError("ProgMesh::addFace(): degenerate faces not accepted.");
00534
00535
00536
00537
00538 this->vertices[v1].getUnitLengthNormalWith(
00539 vertices[v2], vertices[v3]);
00540
00541 int faceIndex = faces.size();
00542
00543 EdgePtr e1 = addEdge (faceIndex, 0, v1, v2);
00544 EdgePtr e2 = addEdge (faceIndex, 1, v2, v3);
00545 EdgePtr e3 = addEdge (faceIndex, 2, v3, v1);
00546 Face newFace (e1,e2,e3);
00547
00548 faces.push_back (newFace);
00549 }
00550
00551
00552
00553 int ProgMesh::addVertex (mfloat x, mfloat y, mfloat z)
00554 {
00555 VertexQuadric v(x,y,z);
00556 vertices.push_back (v);
00557 return (vertices.size() - 1);
00558 }
00559
00560
00561
00562 int ProgMesh::addVertexWithColor (mfloat x, mfloat y, mfloat z, const RgbByte &color)
00563 {
00564 int index = addVertex(x,y,z);
00565
00566 colorMap[index] = color;
00567
00568 return index;
00569 }