/Users/craigcornelius/Projects/SPRING Mac Release 0.2/facearray.cpp

Go to the documentation of this file.
00001 // $Id: facearray.cpp,v 1.72 2006/05/25 22:23:47 craig Exp $
00002 #include "face.h"
00003 #include "facearray.h"
00004 #include "object.h"
00005 #include "objectarray.h"
00006 #include <stdio.h>
00007 #include <stdlib.h>
00008 #ifdef _WIN32
00009 #include <glut.h>
00010 #else
00011 #include <GLUT/glut.h>
00012 #include <OpenGL/gl.h>
00013 #endif
00014 
00015 #include <string>
00016 
00017 using namespace std;
00018 
00019 const char* FaceArray::rcsid = "@(#) $Id: facearray.cpp,v 1.72 2006/05/25 22:23:47 craig Exp $ $Copyright: (c)2001 National Biocomputation Center, Stanford University $";
00020 int FaceArray::debug = 0;
00021 
00022 FaceArray::FaceArray(NodeArray* nodearray_p_in, EdgeArray* edgearray_p_in) 
00023 : nodearray_p(nodearray_p_in), edgearray_p(edgearray_p_in)
00024 {
00025     faces = NULL;
00026     numfaces = maxfaces = 0;
00027 }
00028 
00029 FaceArray::~FaceArray() 
00030 {
00031     // go through and free memory
00032     reset();
00033     
00034     // and set some noticable values
00035     numfaces = maxfaces = -1;
00036 }
00037 
00038 void FaceArray::reset(void) 
00039 {
00040     if (faces) {
00041         // go through and delete each face
00042         for (int i=0; i<numfaces; i++)
00043             delete faces[i];
00044         
00045         // free up the array itself
00046         delete [] faces;
00047     }
00048     
00049     // and reset values
00050     numfaces = maxfaces = 0;
00051 }
00052 
00053 // the same face, or if the node is part of the edge, it returns NULL.
00054 Face* FaceArray::getFace(Edge *e, Node *n)
00055 {
00056     // check that n is not one of the node which defines e!!!
00057     if( (n == e->getNodeLink(0)) || (n == e->getNodeLink(1))) {
00058         cerr << "The node cannot be one of the edge link!!" << endl;
00059         return NULL;
00060     }
00061     
00062     for(int i = 0; i < e->numFaceLinks(); i ++){
00063         Face *curFace = e->getFaceLink(i);
00064         for(int j = 0; j < 3; j ++)
00065             if(n == curFace->getNodeLink(j))
00066                 return curFace;
00067     }
00068     
00069     cerr << "The node is not 'adjacent' to the edge!" << endl;
00070     return NULL; //in case the node is not "adjacent" to the edge...
00071 }
00072 
00073 int FaceArray::getIndex(Face* f)
00074 {
00075     // loop through, looking for it
00076     for (int i=0; i<numfaces; i++)
00077         if (faces[i] == f)
00078             return(i);
00079         
00080         // didn't find it
00081         return(-1);
00082 }
00083 
00084 void FaceArray::allocateFaces(int maxfaces_in) 
00085 { 
00086     maxfaces = maxfaces_in;
00087     faces = new Face*[maxfaces]; 
00088     numfaces=0; 
00089     if (!faces) printf("Could not allocate space for %d faces\n", maxfaces);
00090 }
00091 
00092 int FaceArray::addFace()
00093 {
00094     faces[numfaces] = new Face;
00095     if (numfaces >= maxfaces) {
00096         cerr << "FaceArray::addFace()- blew bounds of array (" << maxfaces 
00097             << ")!\n";
00098         return(numfaces);
00099     }
00100     
00101     // return index of this guy and bump counter up
00102     return(numfaces++); 
00103 }
00104 
00105 
00106 int FaceArray::addFace(int i1, int i2, int i3)
00107 { 
00108     int index = addFace();
00109     faces[index]->init(nodearray_p, edgearray_p, this, i1,i2,i3); 
00110     return(index);
00111 }
00112 
00113 
00114 /* function to open the mesh data file and extract the data into globals
00115 * faces[] and numfaces */
00116 int FaceArray::getMeshFaceData(FILE *meshfile)
00117 {
00118     char s[MAXLINE];
00119     int numfaces_given, numedges_given;
00120     
00121     // get the number of faces from the first line
00122     if (myfgets(s, MAXLINE, meshfile) == NULL) {
00123         printf("No lines in face data file\n");
00124         return(0);
00125     }
00126     if (sscanf(s, "%d", &numfaces_given) != 1) {
00127         printf("Could not read numfaces\n");
00128         return(0);
00129     }
00130     printf("%d faces\n", numfaces_given);
00131     
00132     // allocate space for Face objects + 100% for new faces
00133     allocateFaces(numfaces_given * 2);
00134     
00135     // allocate space for Edge objects
00136     numedges_given = 3 * numfaces_given;    // usually 2xnumfaces = numedges
00137     printf("%d maxedges\n", numedges_given);
00138     edgearray_p->allocateEdges(numedges_given);
00139     
00140     // loop through and get data for each face
00141     for (int i=0; i<numfaces_given; i++) {
00142         if (myfgets(s, MAXLINE, meshfile) == NULL) {
00143             printf("Not enough faces in data file\n");
00144             return(0);
00145         }
00146         
00147         { // initialize face with current data line
00148             int i1, i2, i3;
00149             int numread = sscanf(s, "%d %d %d", &i1, &i2, &i3);
00150             
00151             if (numread != 3) {
00152                 printf("Bad read on face %d- '%d %d %d' - IGNORED\n", i, i1,i2,i3);
00153                 continue;
00154             }
00155             
00156 #ifdef DO_READ_SANITY_CHECKS
00157             // good read: set face info (this will also take care of edges!!)
00158             int new_index = addFace(i1,i2,i3);
00159             
00160             // do a sanity check to make sure
00161             Face* new_face = getFace(new_index);
00162             int ok = new_face->SanityCheck(this);
00163             
00164             // if there was a problem (adding > 2 faces to a edge, etc), delete
00165             if (!ok) {
00166                 new_face->unlink();
00167                 DeleteFace(new_face);
00168             }
00169 #else
00170             // good read: set face info (this will also take care of edges!!)
00171             addFace(i1,i2,i3);
00172 #endif
00173         }
00174         
00175     }
00176     
00177     // return success
00178     return(1);
00179 }
00180 
00181 /* function to open the mesh data file and extract the data into globals
00182 * faces[] and numfaces */
00183 int FaceArray::getSMFFaceData(FILE *meshfile)
00184 {
00185     char s[MAXLINE];
00186     int i, numfaces_given, numedges_given;
00187     
00188     // read file once to get the number of verts and polys
00189     numfaces_given = 0;
00190     while (!feof(meshfile)) {
00191         char s[256];
00192         fgets(s, 256, meshfile);
00193         if (feof(meshfile)) break;
00194         switch (s[0]) {
00195         case 'f' : numfaces_given++; break;
00196         case 'e' : //edge
00197         case 'v' : // vertex 
00198         case '#' : // comment
00199         default  : // who knows?
00200             break;
00201         }
00202     }
00203     
00204     // reset input file pointer
00205     fseek(meshfile, 0, SEEK_SET);
00206     
00207     printf("%d faces\n", numfaces_given);
00208     
00209     // allocate space for Face objects + 50% for new faces
00210     allocateFaces((int)(numfaces_given * 1.5));
00211     
00212     // allocate space for Edge objects
00213     if(edgearray_p->getNumEdges()==0)
00214     {
00215         numedges_given = 3 * numfaces_given;    // usually 2xnumfaces = numedges
00216         printf("%d maxedges\n", numedges_given);
00217         edgearray_p->allocateEdges(numedges_given);
00218     }
00219     
00220     // loop through and get data for each face
00221     for (i = 0; i < numfaces_given; i++) {
00222         do {
00223             if (myfgets(s, MAXLINE, meshfile) == NULL) {
00224                 printf("Not enough faces in data file\n");
00225                 return(0);
00226             }
00227         } while (s[0] != 'f');
00228         
00229         { // initialize face with current data line
00230             int i1, i2, i3;
00231             int numread = sscanf(s, "%*c %d %d %d", &i1, &i2, &i3);
00232             
00233             if (debug) cerr << "Face #" << i << ": " << i1 << " " 
00234                 << i2 << " " << i3 << endl;
00235             
00236             if (numread != 3) {
00237                 printf("Bad read on face %d- '%d %d %d' - IGNORED\n", i, i1,i2,i3);
00238                 continue;
00239             }
00240             
00241             // SMF is 1-based, we are 0-index-based
00242             i1--; i2--; i3--;
00243             
00244 #ifdef DO_READ_SANITY_CHECKS
00245             // good read: set face info (this will also take care of edges!!)
00246             int new_index = addFace(i1,i2,i3);
00247             
00248             // do a sanity check to make sure
00249             Face* new_face = getFace(new_index);
00250             int ok = new_face->SanityCheck(this);
00251             
00252             // if there was a problem (adding > 2 faces to a edge, etc), delete
00253             if (!ok) {
00254                 new_face->unlink();
00255                 DeleteFace(new_face);
00256             }
00257 #else
00258             // good read: set face info (this will also take care of edges!!)
00259             addFace(i1,i2,i3);
00260 #endif
00261         }
00262         
00263     }
00264     
00265     // return success
00266     return(1);
00267 }
00268 
00269 int FaceArray::getOBJFaceData(FILE *meshfile)
00270 {
00271     char s[MAXLINE];
00272     int i, numfaces_given, numedges_given;
00273     
00274     // read file once to get the number of verts and polys
00275     numfaces_given = 0;
00276     while (!feof(meshfile)) {
00277         char s[256];
00278         fgets(s, 256, meshfile);
00279         if (feof(meshfile)) break;
00280         switch (s[0]) {
00281         case 'f' : numfaces_given++; break;
00282         case 'g' : // group
00283         case 'v' : // vertex 
00284         case '#' : // comment
00285         default  : // who knows?
00286             break;
00287         }
00288     }
00289     
00290     // reset input file pointer
00291     fseek(meshfile, 0, SEEK_SET);
00292     
00293     printf("%d faces\n", numfaces_given);
00294     
00295     // allocate space for Face objects + 50% for new faces
00296     // (could have rects given, so is 2x num face lines
00297     allocateFaces((int)(numfaces_given * 2.5));
00298     
00299     // allocate space for Edge objects
00300     if(edgearray_p->getNumEdges()==0)
00301     {
00302         numedges_given = 6 * numfaces_given;    // usually 2xnumfaces = numedges
00303         printf("%d maxedges\n", numedges_given);
00304         edgearray_p->allocateEdges(numedges_given);
00305     }
00306     
00307     // loop through and get data for each face
00308     for (i = 0; i < numfaces_given; i++) {
00309         do {
00310             if (myfgets(s, MAXLINE, meshfile) == NULL) {
00311                 printf("Not enough faces in data file\n");
00312                 return(0);
00313             }
00314         } while (s[0] != 'f');
00315         
00316         { // initialize face with current data line
00317             int i1, i2, i3, i4;
00318             char arg1[20], arg2[20], arg3[20], arg4[20];        
00319             // currently only handle triangles
00320             int numread = sscanf(s, "%*s %s %s %s %s", arg1, arg2, arg3, arg4);
00321             i1 = atoi(arg1); i2 = atoi(arg2); i3 = atoi(arg3); i4 = atoi(arg4);
00322             
00323             if (debug) {
00324                 cerr << "Face #" << i << ": " << i1 << " " 
00325                     << i2 << " " << i3 << endl;
00326                 if (numread > 3) 
00327                     cerr << "Face #" << i << ": " << i2 << " " 
00328                     << i3 << " " << i4 << endl;
00329             }
00330             
00331             // OBJ is 1-based, we are 0-index-based
00332             i1--; i2--; i3--; i4--;
00333             
00334             // good read: set face info (this will also take care of edges!!)
00335             addFace(i1,i2,i3);
00336             if (numread > 3) addFace(i1,i3,i4);
00337         }
00338         
00339     }
00340     
00341     // return success
00342     return(1);
00343 }
00344 
00345 void FaceArray::SaveMeshFaceData(ostream& os)
00346 {
00347     os << numfaces << endl;
00348     for (int i=0; i<numfaces; i++)
00349         faces[i]->SaveAsMesh(os);
00350 }
00351 
00352 void FaceArray::SaveSMFFaceData(ostream& os)
00353 {
00354     nodearray_p->CacheIndices();
00355     for (int i=0; i<numfaces; i++) {
00356         Face* f = getFace(i);
00357         os << "f";
00358         for (int j=0; j<3; j++) {
00359             Node* n = f->getNodeLink(j);
00360             os << " " << n->getCachedIndex() + 1;       // SMF is 1-index based
00361         }
00362         os << endl;
00363     }
00364 }
00365 
00366 void FaceArray::SaveVRMLFaceData(ostream& os)
00367 {
00368     nodearray_p->CacheIndices();
00369     for (int i=0; i<numfaces; i++) {
00370         Face* f = getFace(i);
00371         for (int j=0; j<3; j++) {
00372             Node* n = f->getNodeLink(j);
00373             os << "    " << n->getCachedIndex() << ", ";
00374         }
00375         os << "-1,\n";
00376     }
00377 }
00378 
00379 void FaceArray::SaveSTLFaceData(ostream& os)
00380 {
00381     for (int i=0; i<numfaces; i++) {
00382         Face* f = getFace(i);
00383         
00384         // give it the normal
00385         Point3D normal = f->getNormal();
00386         os << "FACET NORMAL " << normal << "\n";
00387         
00388         // give it the vertex info
00389         os << "OUTER LOOP\n";
00390         for (int j=0; j<3; j++) {
00391             Node* n = f->getNodeLink(j);
00392             os << "VERTEX " << n->p.x << " " << n->p.y << " " << n->p.z << "\n";
00393         }
00394         os << "ENDLOOP\n";
00395         os << "ENDFACET\n";
00396     }
00397 }
00398 
00399 /* Function for drawing faces */
00400 void FaceArray::DrawFaces(int do_texture)
00401 {
00402     // find out if we're in select (picking) mode.  We do this because
00403     // the glLoadName slows things down quite a bit- a new token per triangle!
00404     // (and even if we're just doing a callobj()!)
00405     // We should only do this if in picking mode...
00406     
00407     GLint rendermode;
00408     glGetIntegerv(GL_RENDER_MODE, &rendermode);
00409     if (debug) cerr << "DrawFaces(): rendermode = " << rendermode << endl;
00410     
00411     if (rendermode == GL_RENDER) {
00412         { // draw the triangles
00413             glBegin(GL_TRIANGLES);
00414             for (int i = 0; i < numfaces; i++)
00415                 faces[i]->draw(do_texture);
00416             glEnd();
00417         }
00418     }
00419     else {      // assume GL_SELECT
00420         for (int i = 0; i < numfaces; i++) {
00421             // must be before glBegin for it to pick it up
00422             glPushName(i / 65535);      // push on most significant word
00423             glPushName(i % 65535);      // push on least significant word
00424             glBegin(GL_TRIANGLES);
00425             
00426             // do the draw (no texture needed)
00427             faces[i]->draw(0);
00428             
00429             // pop `em off
00430             glEnd();
00431             glPopName();        // pop off least significant word
00432             glPopName();        // pop off most significant word
00433         }
00434     }
00435 }
00436 
00437 void FaceArray::drawlabels(float offset)
00438 {
00439     for (int i=0; i<numfaces; i++)
00440         faces[i]->drawlabel(offset);
00441 }
00442 
00443 void FaceArray::drawmarkers()
00444 {
00445     for (int i=0; i<numfaces; i++)
00446         faces[i]->drawmarker();
00447 }
00448 
00449 void FaceArray::drawnormals()
00450 {
00451     glBegin(GL_LINES);
00452     glColor3f(1.0, 0.5, 1.0); // draw the normals in light purple
00453     for (int i=0; i<numfaces; i++)
00454         faces[i]->drawnormal();
00455     glEnd();
00456 }
00457 
00458 // function to compute the normals of each face 
00459 void FaceArray::computeNormals(void)
00460 {
00461     for (int i = 0; i < numfaces; i++)
00462         faces[i]->computenormal();
00463 }
00464 
00465 void FaceArray::computeIsobarys(void)
00466 {
00467     for (int i = 0; i < numfaces; i++)
00468         faces[i]->computeisobary();
00469 }
00470 
00471 void FaceArray::DeleteFace(int index)
00472 {
00473     if (debug) cerr << "FaceArray::DeleteFace(" << index << ")\n";
00474     
00475     // sanity check
00476     if (index < 0) return;
00477     
00478     // delete the one we've got
00479     delete faces[index];
00480     
00481     // pack the rest all down
00482     for (int i=index; i<numfaces-1; i++) 
00483         faces[i] = faces[i+1];
00484     
00485     // and decrement number of faces
00486     numfaces--;
00487 }
00488 
00489 void FaceArray::DeleteFace(Face* f)
00490 {
00491     if (debug) cerr << "FaceArray::DeleteFace(" << f << ")\n";
00492     
00493     // get index of face
00494     int index = getIndex(f);
00495     
00496     // do the delete
00497     DeleteFace(index);
00498 }
00499 
00500 void FaceArray::EraseFace(Face * f)
00501 {
00502     Face *tempFace;
00503     
00504     tempFace = f;
00505     f->unlink();
00506     DeleteFace( tempFace );
00507 }
00508 
00509 void FaceArray::EraseFacesOfColor(int color)
00510 {
00511     if (debug) cerr << "EraseFacesOfColor()\n";
00512     
00513     int open_slot = 0;
00514     for (int i = 0; i < numfaces; i++) {
00515         Face* face = getFace(i);
00516         
00517         // assume did vertex coloring and other nodes have same color
00518         Node* n = face->getNodeLink(0); 
00519         if (n->getPartId() == color) {  
00520             face->unlink();     // unlink it from its friends
00521         }
00522         else { // save it
00523             *faces[open_slot] = *faces[i];
00524             open_slot++;
00525         }
00526     }
00527     
00528     // reset the number of faces left
00529     numfaces = open_slot;
00530 }
00531 
00532 void FaceArray::DeleteAllFaces()
00533 {
00534     if (debug) cerr << "DeleteAllFaces()\n";
00535     
00536     // turns out, all we have to do is to reset the number (is static allocation)
00537     numfaces = 0;
00538 }
00539 
00540 void FaceArray::WriteDXF(ostream& os)
00541 {
00542     for (int i=0; i<numfaces; i++) {
00543         Face* face = getFace(i);
00544         os << "0\n3DFACE\n";
00545         Node* node1 = face->getNodeLink(0);
00546         Node* node2 = face->getNodeLink(1);
00547         Node* node3 = face->getNodeLink(2);
00548         os << "10\n" << node1->p.x << "\n20\n" << node1->p.y << "\n30\n" 
00549             << node1->p.z << endl;
00550         os << "11\n" << node2->p.x << "\n21\n" << node2->p.y << "\n31\n" 
00551             << node2->p.z << endl;
00552         os << "12\n" << node3->p.x << "\n22\n" << node3->p.y << "\n32\n" 
00553             << node3->p.z << endl;
00554         os << "13\n" << node3->p.x << "\n23\n" << node3->p.y << "\n33\n" 
00555             << node3->p.z << endl;
00556     }
00557 }
00558 
00559 double FaceArray::getSurfaceArea()
00560 {
00561     if (debug) cerr << "FaceArray::getSurfaceArea()\n";
00562     
00563     // loop over all faces, accumulating surface area
00564     double area_sum = 0.0;
00565     for (int i=0; i<numfaces; i++) {
00566         Face* face = getFace(i);
00567         area_sum += face->getArea();
00568     }
00569     
00570     // and return it
00571     return(area_sum);
00572 }
00573 
00574 double FaceArray::getVolume()
00575 {
00576     if (debug) cerr << "FaceArray::getVolume()\n";
00577     
00578     // get the minimum value in the y direction (min.y of bbox)
00579     Point3D min, max;
00580     nodearray_p->getBoundingBox(&min, &max);
00581     
00582     // loop over all faces, accumulating volume
00583     double volume_sum = 0.0;
00584     for (int i=0; i<numfaces; i++) {
00585         Face* face = getFace(i);
00586         Point3D n = face->getNormal();
00587         Point3D center = face->getCenter();
00588         
00589         double height = center.y - min.y;
00590         double volume = height * face->getShadowArea();
00591         
00592         // see which way the face is pointing
00593         if (n.y < 0) // pointing in opposite direction as x-z plane normal=neg vol 
00594             volume = -volume;
00595         
00596         // accumulate the volume of this face
00597         volume_sum += volume;
00598     }
00599     
00600     // return the value
00601     return(volume_sum);
00602 }
00603 
00604 double FaceArray::getExactZVolume(int Num_Face_Surface)
00605 {
00606     if (debug) cerr << "FaceArray::getExactZVolume()\n";
00607     // Note that I use Num_Face_Surface and not numfaces on purpose, 
00608     // because if the object has been extruded, NumFaces != numfaces
00609     // and we really want to use NumFaces which should be the number
00610     // of faces of the object before it was extruded.
00611     
00612     // loop over all faces, accumulating volume
00613     double volume_sum = 0.0;
00614     for (int i=0; i<Num_Face_Surface; i++) 
00615         volume_sum += getFace(i)->ZVolume();
00616     return volume_sum;
00617 }
00618 
00619 // this function creates a new node at the given S, then calls the
00620 // function below.  We created it because sometimes we need to have
00621 // the new node created, and other times (like when we're splitting
00622 // two adjacent faces), we already have the split node
00623 Node* FaceArray::subdivideFace(Face *initial_p, Point3D S, Face* *t1_p, 
00624                                Face* *t2_p, Face* *t3_p) 
00625 {
00626     cerr << "FaceArray::subdivideFace(" << initial_p << ", " << S << ", "
00627         << t1_p << "," << t2_p << "," << t3_p << "," << ")\n";
00628     
00629     // S becomes a new Node 
00630     cerr << "initial_p is face # " << initial_p->getIndex() << endl;
00631     int index_S = nodearray_p->addNode(S);
00632     Node* node_S = nodearray_p->getNode(index_S);
00633     cerr << " Created new node S of index " << index_S <<": "<< *node_S << endl;
00634     
00635     // and call the other subdivide
00636     Node* ret_ptr = subdivideFace(initial_p, node_S, t1_p, t2_p, t3_p);
00637     
00638     // test if we were unsuccessful (if so, kill our created node)
00639     if (ret_ptr == NULL) nodearray_p->DeleteNode(node_S);
00640     
00641     // and return their status/new_node
00642     return(ret_ptr);
00643 }
00644 
00645 // subdivides a face in 2 or 3 faces in function of the position of the point
00646 // in the triangle. If the point is outside, it returns NULL, otherwise it
00647 // returns a pointer to the new node created due to the split and the faces
00648 // that were created
00649 // notice: this function assumes the point S is in the plane of the triangle.
00650 Node* FaceArray::subdivideFace(Face *initial_p, Node* node_S, Face* *t1_p, 
00651                                Face* *t2_p, Face* *t3_p) 
00652 {
00653     cerr << "FaceArray::subdivideFace(" << initial_p << ", " << node_S << ", "
00654         << t1_p << "," << t2_p << "," << t3_p << "," << ")\n";
00655     cerr << "SUBDIVIDING FACE: " << *initial_p << endl;
00656 
00657     const double precision = 0.001;
00658     double dist, dot;
00659     Point3D center = initial_p->getCenter();
00660     Node *p[3];
00661     p[0] = initial_p->getNodeLink(0);
00662     p[1] = initial_p->getNodeLink(1);
00663     p[2] = initial_p->getNodeLink(2);
00664     
00665     Point3D p_S[3];
00666     Point3D p_p[3];
00667     Point3D p_center[3];
00668     Point3D cross1, cross2;
00669     Face *t1, *t2, *t3;
00670 
00671     for (int i = 0; i < 3; i++){
00672         p_S[i] = node_S->p - p[i]->p;
00673         
00674         // ie, if S is too close to one of the vertices, we do not subdivide
00675         if (p_S[i].Length() < precision) { 
00676             cerr << "too close to vertex (length = " << p_S[i].Length() 
00677                 << "<" << precision << "\n";
00678             return(NULL); 
00679         }
00680         
00681         p_p[i] = p[(i + 1) % 3]->p - p[i]->p;
00682         p_center[i] = center - p[i]->p;
00683         cross1 = p_S[i].Cross(p_p[i]);
00684         cross2 = p_center[i].Cross(p_p[i]);
00685         dot = cross1.Dot(cross2);
00686         
00687         if (dot < -precision) { 
00688             cerr << "dot < 0 (=" << dot << ")\n"; 
00689             return(NULL); 
00690         }
00691         
00692         dist = cross1.Length() / p_p[i].Length();
00693         
00694         //case when S in on an edge of the initial face so we subdivide in 2 faces
00695         if(dist <= precision) {
00696             cerr << " split into 2 faces\n";
00697             
00698             //should destroy the old sphere tree before mucking with subdivide
00699             // avoid coredumps from other objects colliding with this one
00700             getObject()->getObjectArray()->ResetCollisions();
00701             getObject()->DestroySphereTree();
00702             
00703             // unlink the parent face from its nodes and edges
00704             // this way, the edges will be open for the new faces to bind to
00705             initial_p->unlink();
00706             
00707             // and delete the face from our list
00708             DeleteFace(initial_p);
00709             
00710             // create 2 new faces
00711             int new_index1 = addFace(); int new_index2 = addFace();
00712             t1 = getFace(new_index1); t2 = getFace(new_index2);
00713             
00714             // initialize our new faces and link in to new edges
00715             t1->init(nodearray_p, edgearray_p, this, node_S, p[(i+1) % 3],
00716                 p[(i+2)%3]);
00717             t2->init(nodearray_p, edgearray_p, this, node_S, p[(i+2) % 3],p[i]);
00718             cerr << "split_node = " << *node_S << endl;
00719             cerr << "subtri t1: " << *t1 << endl;
00720             cerr << "subtri t2: " << *t2 << endl;
00721             
00722             // tell new faces to compute their normals
00723             t1->computenormal();
00724             t2->computenormal();
00725             
00726             // set up faces for return
00727             if (t1_p) *t1_p = t1;
00728             if (t2_p) *t2_p = t2;
00729             if (t3_p) *t3_p = NULL;
00730             
00731             getObject()->CreateSphereTree();
00732             return(node_S);
00733         }
00734     }
00735     
00736     /* case when S inside the initial face so we subdivide in 3 faces */
00737     cerr << " split into 3 faces\n";
00738     
00739     //should destroy the old sphere tree before mucking with subdivide
00740     // avoid coredumps from other objects colliding with this one
00741     getObject()->getObjectArray()->ResetCollisions();
00742     getObject()->DestroySphereTree();
00743     
00744     // create the 3 new faces
00745     int new_index1 = addFace();
00746     int new_index2 = addFace(); 
00747     int new_index3 = addFace();
00748     t1 = getFace(new_index1); 
00749     t2 = getFace(new_index2); 
00750     t3 = getFace(new_index3);
00751     
00752     // unlink the parent face from its nodes and edges
00753     // this way, the edges will be open for the new faces to bind to
00754     initial_p->unlink();
00755     
00756     // delete it from our list
00757     DeleteFace(initial_p);
00758     
00759     // initialize our new faces and link in to new edges
00760     t1->init(nodearray_p, edgearray_p, this, node_S, p[1], p[2]);
00761     t2->init(nodearray_p, edgearray_p, this, node_S, p[2], p[0]);
00762     t3->init(nodearray_p, edgearray_p, this, node_S, p[0], p[1]);
00763     
00764     // tell new faces to compute their normals
00765     t1->computenormal();
00766     t2->computenormal();
00767     t3->computenormal();
00768     
00769     cerr << "split_node = " << *node_S << endl;
00770     cerr << "subtri t1: " << *t1 << endl;
00771     cerr << "subtri t2: " << *t2 << endl;
00772     cerr << "subtri t3: " << *t3 << endl;
00773     
00774     if (t1_p) *t1_p = t1;
00775     if (t2_p) *t2_p = t2;
00776     if (t3_p) *t3_p = t3;
00777     
00778     getObject()->CreateSphereTree();
00779     return(node_S);
00780 }
00781 
00782 /* This function undoes the changes done by subdivideFace -- given a node, it
00783 * deletes this node, incident faces and edges, and creates a new face which
00784 * is the union of the deleted faces */
00785 Face* FaceArray::unSubdivideFace(Node *n_in)
00786 {
00787     printf("unsubdividing ...\n");
00788     // destroy old sphere tree before changes
00789     // avoid coredumps from other objects colliding with this one
00790     (getObject()->getObjectArray())->ResetCollisions();
00791     getObject()->DestroySphereTree();
00792     int i;
00793     int n_facedegree = n_in->numFaceLinks();
00794     int n_edgedegree = n_in->numEdgeLinks();
00795     Face* f[3];
00796     Edge* e[3];
00797     Node* n[3];
00798     // make sure n is connected to 3 edges and 2 or 3 faces (2 cases of subdiv)
00799     if (n_facedegree < 2 || n_facedegree > 3 || n_edgedegree != 3) {
00800         printf("node not created by subdivideFace, or resubdivided fd %d ed %d\n",
00801             n_facedegree, n_edgedegree);
00802         // if we subdivided and then resubdivided one of the new faces, we must
00803         // unsubdivide in reverse order, or else it will bail out here!!
00804         cerr << "more node info: " << *n_in << endl;
00805         return(NULL);
00806     }
00807     //get the incident faces and edges, and the 3 nodes connected to these edges
00808     for (i = 0; i < n_facedegree; i++) {
00809         f[i] = n_in->getFaceLink(i);
00810         cerr << "old face " << *f[i] << endl;
00811     }
00812     for (i = 0; i < n_edgedegree; i++) {
00813         e[i] = n_in->getEdgeLink(i);
00814         n[i] = e[i]->getOtherNode(n_in);
00815     }
00816     // now unlink the faces from adjacent nodes and edges, and delete them
00817     for (i = 0; i < n_facedegree; i++) {
00818         f[i]->unlink();
00819         DeleteFace(f[i]);
00820     }
00821     // now unlink the edges from adjacent nodes and delete them
00822     for (i = 0; i < n_edgedegree; i++) {
00823         n[i]->deleteEdgeLink(e[i]);
00824         n_in->deleteEdgeLink(e[i]);  //unnecessary since we're about to delete it
00825         edgearray_p->DeleteEdge(e[i]);
00826     }
00827     // now delete the given node
00828     nodearray_p->DeleteNode(n_in);
00829     // now create a new face from the 3 nodes
00830     i = addFace();
00831     Face* f_out = getFace(i);
00832     f_out->init(nodearray_p, edgearray_p, this, n[0], n[1], n[2]);
00833     f_out->computenormal(); // why?
00834     cerr << "new face " << *f_out << endl;
00835     getObject()->CreateSphereTree();
00836     return(f_out);
00837 }
00838 
00839 void FaceArray::SanityCheck(NodeArray* real_na_p, EdgeArray* real_ea_p)
00840 {
00841     string s;
00842     
00843     if (!nodearray_p) s += "nodearray is NULL!";
00844     if (nodearray_p != real_na_p) s += "nodearray is BAD!";
00845     if (!edgearray_p) s += "edgearray is NULL!";
00846     if (edgearray_p != real_ea_p) s += "edgearray is BAD!";
00847     if (numfaces < 0) s += "numfaces < 0!";
00848     if (numfaces > maxfaces) s += "numfaces > maxfaces!";
00849     if (maxfaces < 0) s += "maxfaces < 0!";
00850     
00851     if (s.size() > 1) 
00852         cerr << "FaceArray is INSANE: " << s.c_str() << endl;
00853     
00854     // check all our faces
00855     for (int i=0; i<numfaces; i++)
00856         faces[i]->SanityCheck(this);
00857 }
00858 
00859 // Eliminates any faces that are insane
00860 void FaceArray::Cleanup()
00861 {
00862     // check all our faces
00863     for (int i=0; i<numfaces; i++) {
00864         Face* f = faces[i];
00865         if (!f->SanityCheck(this)) {    // is insane- kill it
00866             f->unlink();        // unlink it from it's edges/nodes
00867             DeleteFace(i);      // and kill it
00868             
00869             i--;        // backup the counter because the DeleteFace() shifted all down
00870         }
00871     }
00872 }
00873 
00874 double FaceArray::DistanceToNearestFace(Point3D p)
00875 {
00876     double min_dist = 1e20;
00877     for (int i=0; i<numfaces; i++) {
00878         Face* f = getFace(i);
00879         
00880         // NOTE: THIS IS NOT THE RIGHT FUNCTION!  WE NEED A
00881         // DistanceToPoint(p) FUNCTION THAT TELLS THE DISTANCE
00882         // FROM THE GIVEN POINT TO THE FACE (NOT JUST IT'S PLANE)
00883         //double cur_dist = fabs(f->PlaneDistanceToPoint(p));
00884         
00885         // for now, approximate by distance to center
00886         Point3D face_center = f->getCenter();
00887         double cur_dist = p.Dist(face_center);
00888         
00889         if (cur_dist < min_dist)
00890             min_dist = cur_dist;
00891     }
00892     
00893     return(min_dist);
00894 }
00895 
00896 
00897 //finds the closest face of the object to the given pt point.
00898 Face* FaceArray::ClosestFaceToPoint(Point3D pt)
00899 {
00900     int numF = getNumFaces();
00901     Face* current = getFace(0);
00902     Face* closest = current;
00903     double minDist = current->FaceDistanceToPoint(pt); 
00904     for (int i = 1; i < numF; i ++){
00905         current = getFace(i);
00906         double currDist = current->FaceDistanceToPoint(pt);
00907         if( minDist > currDist ){
00908             minDist = currDist;
00909             closest = current;
00910         }
00911     }
00912     
00913     return(closest);
00914 }
00915 
00916 // this function reorders the facearray based on a viewing matrix
00917 // in this way, we can then display the triangles from farthest Z-value
00918 // to nearest Z-value (w.r.t. the viewer) to make transparency look good
00919 // so, this function gives us the array as farthest to nearest faces
00920 void FaceArray::ReorderFacesBasedOnViewingMatrix(double* model, double* proj, 
00921                                                  GLint* view)
00922 {
00923     // get some local storage
00924     double* depths = new double[getNumFaces()];
00925     double min = 1e20, max = -1e20;
00926     
00927     { // for each face, project it to the viewer and save the resulting depth
00928         for (int i=0; i<getNumFaces(); i++) {
00929             // get the face, then its center
00930             Face* f = getFace(i);
00931             Point3D center = f->getCenter();
00932             
00933             // project it
00934             double projx, projy, depth;
00935             gluProject(center.x,center.y,center.z, model,proj,view, 
00936                 &projx,&projy,&depth);
00937             
00938             // save the value
00939             depths[i] = depth;
00940             if (depth > max) max = depth;
00941             if (depth < min) min = depth;
00942         }
00943     }
00944     
00945     // debugging
00946     if (debug) cerr << "Max = " << max << ", " << "Min = " << min << endl;
00947     
00948     { // now reorder all the triangles in our list based on their depth
00949         // implements a very dumb O(n^2) sort
00950         for (int i=0; i<getNumFaces(); i++) {
00951             for (int j=i+1; j<getNumFaces(); j++) {
00952                 
00953                 // if face i is farther than face j, swap `em
00954                 if (depths[i] < depths[j]) {
00955                     Face* tmp = faces[i];
00956                     faces[i] = faces[j];
00957                     faces[j] = tmp;
00958                     
00959                     double d_tmp = depths[i];
00960                     depths[i] = depths[j];
00961                     depths[j] = d_tmp;
00962                 }
00963             }
00964         }
00965     }
00966     
00967     // clean up
00968     delete [] depths;
00969 }
00970 
00971 // Note: the Node::getIndex() call is slow, unless we first call 
00972 // NodeArray::CacheIndices(), which we're assuming we have
00973 void FaceArray::GeometryReplicate(GeometryReplicator* gr)
00974 {
00975   if (debug) cerr << "FaceArray::GeometryReplicate(" << gr << ")\n";
00976 
00977   // locals
00978   const int buf_size = 1490;    //1500 is native packet side - need some padding
00979   char buffer[buf_size];
00980 /*
00981   // loop, sending each face's info
00982   for (int i=0; i<getNumFaces(); i++) {
00983         Face* face = getFace(i);
00984         Node* i0 = face->getNodeLink(0);
00985         Node* i1 = face->getNodeLink(1);
00986         Node* i2 = face->getNodeLink(2);
00987         int s = sprintf(buffer, "%c%c%d %d %d %d", GR_CODE, GR_FACE, i, 
00988                 i0->getIndex(), i1->getIndex(), i2->getIndex());
00989         gr->SendMessage(buffer, s);
00990   }
00991 */
00992 
00993         int numNodesInBuffer = 0;
00994         int faceEntry[3];
00995         u_long* netFaceEntry = (u_long*)faceEntry;
00996 
00997         int nodeEntrySize = sizeof(int) + 3*sizeof(int);
00998 
00999         u_long netvalue;
01000 
01001     int s = sprintf(buffer, "%c%c", GR_CODE, GR_FACE);
01002         netvalue = htonl(numNodesInBuffer);
01003         memcpy(&buffer[s],&netvalue,sizeof(int));
01004         s += sizeof(int);
01005     
01006         for (int i=0; i<getNumFaces(); i++) 
01007         {
01008                 if (s + nodeEntrySize < buf_size)
01009                 {
01010                         Face* face = getFace(i);
01011                         Node* i0 = face->getNodeLink(0);
01012                         Node* i1 = face->getNodeLink(1);
01013                         Node* i2 = face->getNodeLink(2);
01014 
01015                         faceEntry[0] = i0->getIndex();
01016                         faceEntry[1] = i1->getIndex();
01017                         faceEntry[2] = i2->getIndex();
01018 
01019                         netFaceEntry[0] = htonl(netFaceEntry[0]);
01020                         netFaceEntry[1] = htonl(netFaceEntry[1]);
01021                         netFaceEntry[2] = htonl(netFaceEntry[2]);
01022 
01023 
01024                         //place the index in the entry
01025                         netvalue = htonl(i);
01026 
01027                         memcpy(&buffer[s],&netvalue,sizeof(int));
01028                         s += sizeof(int);
01029                         //send all the node data
01030                         memcpy(&buffer[s],netFaceEntry,3*sizeof(int));
01031                         s += 3*sizeof(int);
01032 
01033                         numNodesInBuffer++;
01034 
01035                 }
01036 
01037                 if ((s + nodeEntrySize >= buf_size) || (i == getNumFaces() - 1) )
01038                 {
01039                         //copy in the actual number of nodes
01040                         netvalue = htonl(numNodesInBuffer);
01041                         memcpy(&buffer[2],&netvalue,sizeof(int));
01042                         gr->SendMessage(buffer, s);
01043 
01044                         //reload the buffer with the header and reset s
01045                         s = sprintf(buffer, "%c%c", GR_CODE, GR_FACE);
01046                         numNodesInBuffer = 0;
01047                         netvalue = htonl(numNodesInBuffer);
01048                         memcpy(&buffer[2],&netvalue,sizeof(int));
01049                         s += sizeof(int);
01050                 }
01051     }
01052 
01053 
01054 }
01055 
01056 ostream& operator<<(ostream& os, const FaceArray& fa)
01057 {
01058     os << fa.numfaces << endl;
01059     for (int i=0; i<fa.numfaces; i++) {
01060         const FaceArray* fa_p = &fa;
01061         Face* cur_face = ((FaceArray*)fa_p)->getFace(i);
01062         os << (*cur_face) << endl;
01063     }
01064     return(os);
01065 }

Generated on Thu Aug 30 11:03:13 2007 for SPRING Mac by  doxygen 1.5.3