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

Go to the documentation of this file.
00001 /* $Id: edgearray.cpp,v 1.54 2006/05/25 22:23:11 craig Exp $ */
00002 #include "edgearray.h"
00003 #include "object.h"
00004 #include "nodearray.h"
00005 #include "edge.h"
00006 #include "node.h"
00007 #include "object.h"
00008 #include "knot.h"
00009 #ifdef _WIN32
00010 #include <glut.h>
00011 #else
00012 #include <GLUT/glut.h>
00013 #include <OpenGL/gl.h>
00014 #endif
00015 #include <stdlib.h>
00016 
00017 
00018 #include <string>
00019 
00020 using namespace std;
00021 
00022 const char* EdgeArray::rcsid = "@(#) $Id: edgearray.cpp,v 1.54 2006/05/25 22:23:11 craig Exp $ $Copyright: (c)2001 National Biocomputation Center, Stanford University $";
00023 
00024 int EdgeArray::debug = 0;
00025 int default_maxedges = 1000;
00026 
00027 EdgeArray::EdgeArray(NodeArray* nodearray_p_in)
00028 : nodearray_p(nodearray_p_in)
00029 { 
00030     edges = NULL;
00031     numedges = maxedges = 0; 
00032 // !!! TEMPORARY
00033     do_nonlinear = 1;
00034     strcpy(edgefilename, "edge.data");
00035 }
00036 
00037 EdgeArray::~EdgeArray()
00038 { 
00039     reset();
00040     numedges = maxedges = -1;
00041 }
00042 
00043 void EdgeArray::reset(void)
00044 { 
00045     if (edges) {
00046         // delete all the edges
00047         for (int i=0; i<numedges; i++)
00048             delete edges[i];
00049         
00050         // and delete the array itself
00051         delete [] edges; 
00052     }
00053     
00054     numedges = maxedges = 0;
00055 }
00056 
00057 void EdgeArray::scaleRestLengths(double scalefactor)
00058 { 
00059     for (int i=0; i<numedges; i++)
00060         edges[i]->scaleRestLength(scalefactor);
00061 }
00062 
00063 void EdgeArray::computeNewRestLengths()
00064 { 
00065     for (int i=0; i<numedges; i++) 
00066         edges[i]->computeNewRestLength();
00067 }
00068 
00069 int EdgeArray::getIndex(Edge* e)
00070 {
00071     // go look for it
00072     for (int i=0; i<numedges; i++)
00073         if (edges[i] == e) 
00074             return(i);
00075         
00076         // didn't find it
00077         return(-1);
00078 }
00079 
00080 void EdgeArray::setEdgeFilename(char *s)
00081 {
00082     strcpy(edgefilename, s);
00083 }
00084 
00085 void EdgeArray::allocateEdges(int maxedges_in)
00086 { 
00087     numedges=0;
00088     maxedges = maxedges_in;
00089     default_maxedges = maxedges;    // save as new default
00090     edges = new Edge*[maxedges]; 
00091     if (edges == NULL) {
00092         cerr << "EdgeArray: Could not allocate memory for " << maxedges 
00093             << " edges!\n";
00094     }
00095 }
00096 
00097 int EdgeArray::addEdge(int i0, int i1, double restLength,
00098                        double springConstant, double dampConstant) 
00099 { 
00100     //  get the real nodes
00101     Node* n0 = nodearray_p->getNode(i0);
00102     Node* n1 = nodearray_p->getNode(i1);
00103     
00104     // and call the other function
00105     int s = addEdge(n0, n1, restLength, springConstant, 
00106         dampConstant);
00107     
00108     // and report their value
00109     return(s);
00110 }
00111 
00112 int EdgeArray::addEdge(Node* n0, Node* n1, double restLength,
00113                        double springConstant, 
00114                        double dampConstant)
00115 { 
00116     // if no space, go and get some
00117     if (maxedges == 0) allocateEdges(default_maxedges);
00118     
00119     // do it
00120     edges[numedges] = new Edge;
00121     edges[numedges]->init(nodearray_p,this, n0,n1,
00122         restLength, springConstant,dampConstant);
00123     
00124     // if beyond end, report error
00125     if (numedges >= maxedges) {
00126         cerr << "EdgeArray: blew bounds of memory! (" << maxedges << ")\n";
00127         return(numedges);
00128     }
00129     else
00130         return(numedges++);
00131 }
00132 
00133 /* function to open the edge data file and extract the data into
00134 * edges[] and numedges */
00135 int EdgeArray::getEdgeData() {
00136     FILE *edgefile;
00137     char s[MAXLINE];
00138     int numedges_given;
00139     
00140     // open the edge data file
00141     if ((edgefile = fopen(edgefilename, "r")) == NULL) {
00142         printf("Could not open edge data file\n");
00143         return 0;
00144     }
00145     // get the number of edges from the first line
00146     if (myfgets(s, MAXLINE, edgefile) == NULL) {
00147         printf("No lines in edge data file\n");
00148         return 0;
00149     }
00150     if (sscanf(s, "%d", &numedges_given) != 1) {
00151         printf("Could not read numedges\n");
00152         return 0;
00153     }
00154     printf("%d edges\n", numedges_given);
00155     printf("Edge# Node1# Node2#\n");
00156     
00157     // allocate space for Edge objects + 50%
00158     allocateEdges((int)(numedges_given * 1.5));
00159     
00160     // loop through and get data for each edge
00161     for (int i = 0; i < numedges_given; i++) {
00162         if (myfgets(s, MAXLINE, edgefile) == NULL) {
00163             printf("Not enough edges in data file\n");
00164             return 0;
00165         }
00166         
00167         // initialize one edge with current data line
00168         int index = addEdge(0,0,0,0,0);    // create a dummy one
00169         if (edges[index]->init(nodearray_p, this, s) == 0) {    // load it up
00170             printf("edges[%d].init failed\n", i);
00171             return 0;
00172         }
00173         if (debug)
00174             printf("%d %d %d\n", edges[i]->getIndex(),
00175             nodearray_p->getIndex(edges[i]->getNodeLink(0)),
00176             nodearray_p->getIndex(edges[i]->getNodeLink(1)));
00177     }
00178     if (fclose(edgefile) == EOF) {
00179         printf("Could not close edge data file\n");
00180         return 0;
00181     }
00182     
00183     return 1;
00184 }
00185 
00186 void EdgeArray::SaveFrdEdgeData(ostream& os)
00187 {
00188     nodearray_p->CacheIndices();
00189     for (int i=0; i<numedges; i++) {
00190         Edge* ed = getEdge(i);
00191         os << "e";
00192         for (int j=0; j<2; j++) {
00193             Node* n = ed->getNodeLink(j);
00194             os << " " << n->getCachedIndex() + 1;    // Frd is 1-index based (as SMF...)
00195         }
00196         os << endl;
00197     }
00198 }
00199 
00200 int EdgeArray::getFRDEdgeData(FILE *meshfile)
00201 {
00202     char s[MAXLINE];
00203     int i, numedges_given;
00204     
00205     // read file once to get the number of verts and polys
00206     numedges_given = 0;
00207     while (!feof(meshfile)) {
00208         char s[256];
00209         fgets(s, 256, meshfile);
00210         if (feof(meshfile)) break;
00211         switch (s[0]) {
00212         case 'e' : numedges_given++; break;
00213         case 'f' : // faces
00214         case 'v' : // vertex 
00215         case '#' : // comment
00216         default  : // who knows?
00217             break;
00218         }
00219     }
00220     
00221     // reset input file pointer
00222     fseek(meshfile, 0, SEEK_SET);
00223     
00224     printf("%d edges\n", numedges_given);
00225     
00226     // allocate space for Edge objects + 50% for new edges
00227     allocateEdges((int)(numedges_given * 1.5));
00228     
00229     // loop through and get data for each edge
00230     for (i = 0; i < numedges_given; i++) 
00231     {
00232         do 
00233         {
00234             if (myfgets(s, MAXLINE, meshfile) == NULL) 
00235             {
00236                 printf("Not enough edges in data file\n");
00237                 return(0);
00238             }
00239         } while (s[0] != 'e');
00240         
00241         { // initialize Edge with current data line
00242             int i1, i2;
00243             int numread = sscanf(s, "%*c %d %d", &i1, &i2);
00244             
00245             if (debug) cerr << "Edge #" << i << ": " << i1 << " " 
00246                 << i2 << endl;
00247             
00248             if (numread != 2) 
00249             {
00250                 printf("Bad read on edge %d- '%d %d' - IGNORED\n", i, i1,i2);
00251                 continue;
00252             }
00253             
00254             // FRD is 1-based, we are 0-index-based (as SMF...)
00255             i1--; i2--;
00256             
00257 #ifdef DO_READ_SANITY_CHECKS
00258             // good read: set edge info
00259             int new_index = addEdge(i1,i2);
00260             // do a sanity check to make sure
00261             Edge* new_edge = getEdge(new_index);
00262             int ok = new_edge->SanityCheck(this);
00263             
00264             // if there was a problem delete
00265             if (!ok) 
00266             {
00267                 //new_edge->unlink();
00268                 DeleteEdge(new_edge);
00269             }
00270 #else
00271             // good read: set edge info
00272             addEdge(i1,i2);
00273             
00274 #endif
00275         }
00276         
00277     }
00278     
00279     // return success
00280     return(1);
00281 }
00282 
00283 /* function to calculate the torsion force between two faces for every edge,
00284 * and apply this to the exterior nodes of these faces */
00285 void EdgeArray::addTorsions(void)
00286 {
00287     // loop through all the edges
00288     for (int i = 0; i < numedges; i++) {
00289         edges[i]->addTorsion();
00290     }
00291 }
00292 
00293 // Calculates the force vector for each edge based on spring length, spring
00294 // constant, and rest length.
00295 // Requires the position of the end nodes.
00296 // Note that the force is directional, depending if the spring is compressed or streteched.
00297 // Using this avoids computing the force for each end node.
00298 void EdgeArray::ComputeForceVectors(int dampingType)
00299 {
00300         int i;
00301 
00302         switch (dampingType) {
00303         case FULL:
00304                 // Loop over all edges.
00305                 for (i = 0; i < numedges; i++) {
00306                         edges[i]->ComputeSpringForceFullDamp();
00307                 }
00308                 break;
00309         case REL:
00310                 // Loop over all edges.
00311                 for (i = 0; i < numedges; i++) {
00312                         edges[i]->ComputeSpringForceRelDamp();
00313                 }
00314                 break;
00315         default:
00316                 // ??? What about ABS - I think this will be computed in the nodes - more complex.
00317                 for (i = 0; i < numedges; i++) {
00318                         edges[i]->ComputeSpringForce(dampingType);
00319                 }
00320                 break;
00321         }
00322 
00323 }
00324 
00325 // Calculates the force vector for each edge based on spring length, spring3
00326 // constant, and rest length.
00327 // Important: This version increase the force if the distance is too far from the rest length!
00328 // Requires the position of the end nodes.
00329 // Note that the force is directional, depending if the spring is compressed or streteched.
00330 // Using this avoids computing the force for each end node.
00331 void EdgeArray::ComputeForceVectorsNonlinear(int dampingType)
00332 {
00333         // Loop over all edges, computing the non-linear spring force for each.
00334         int i;
00335         for (i = 0; i < numedges; i++) {
00336                 edges[i]->ComputeSpringForceNonlinear(dampingType);
00337         }
00338 }
00339 
00340 // this function projects all the edges of a thread type object onto a given
00341 // plane (the z-plane), and finds all the crossings, as a precursor to 
00342 // finding a knot -- then it finds the knot
00343 void EdgeArray::KnotIdentify(int testing)
00344 {
00345   extern char knotstring[100]; // keeps old global value
00346 
00347   double zdowker[MAXCROSS];
00348   int zorder[MAXCROSS];
00349   int zdk[MAXCROSS/2];
00350   int zcount = 0;
00351   int i, j;
00352 
00353   // one dummy edge, connects first and last nodes to close the knot
00354   Edge edummy;
00355   edummy.init(NULL, NULL, getEdge(numedges-1)->getNodeLink(1),
00356               getEdge(0)->getNodeLink(0));
00357 
00358   // this part actually finds all the 2D crossings
00359   for (i = 0; i < numedges; i++) {
00360     // get info for the first line segment, n1 + s*(n2-n1)
00361     Edge *ea = getEdge(i);
00362     Node *n1 = ea->getNodeLink(0);
00363     Node *n2 = ea->getNodeLink(1);
00364     double x1 = n1->p.x; double y1 = n1->p.y; double z1 = n1->p.z;
00365     double x2 = n2->p.x; double y2 = n2->p.y; double z2 = n2->p.z;
00366 
00367     for (j = i+2; j < numedges+1; j++) {
00368       // get info for the second line segment, n3 + t*(n4-n3)
00369       Edge *eb;
00370       if (j == numedges)
00371         eb = &edummy;
00372       else
00373         eb = getEdge(j);
00374       Node *n3 = eb->getNodeLink(0);
00375       Node *n4 = eb->getNodeLink(1);
00376       double x3 = n3->p.x; double y3 = n3->p.y; double z3 = n3->p.z;
00377       double x4 = n4->p.x; double y4 = n4->p.y; double z4 = n4->p.z;
00378 
00379       // Solve for intersection point when projected to z = 0 plane:
00380       // (see http://astronomy.swin.edu.au/pbourke/geometry/lineline2d/ )
00381       double x2minusx1 = x2 - x1;
00382       double x3minusx1 = x3 - x1;
00383       double x4minusx3 = x4 - x3;
00384       double y2minusy1 = y2 - y1;
00385       double y3minusy1 = y3 - y1;
00386       double y4minusy3 = y4 - y3;
00387       double denom = x2minusx1*y4minusy3 - x4minusx3*y2minusy1;
00388       // check for zero denom (and possibly zero num)
00389       if (denom == 0.0)
00390         ; // skip for now
00391       else {
00392         double snum = x3minusx1*y4minusy3 - y3minusy1*x4minusx3;
00393         double tnum = x3minusx1*y2minusy1 - y3minusy1*x2minusx1;
00394         double s = snum/denom;
00395         double t = tnum/denom;
00396         if (s >= 0.0 && s < 1.0 && t >= 0.0 && t < 1.0) {
00397           if (zcount >= MAXCROSS) {
00398             // too many crossings, bail out
00399             strcpy(knotstring, "too many crossings");
00400             return;
00401           }
00402           // add s,t to make these exact, segment can be in 2 crossings
00403           zdowker[zcount++] = i + s;
00404           if (zdowker[zcount-1] == 0.0) zdowker[zcount-1] = 0.01;
00405           zdowker[zcount++] = j + t;
00406           if (testing)
00407             printf("z Segment %5.2f crosses ", i+s);
00408           // Unproject to get over/under/through
00409           double zs = z1 + s*(z2 - z1);
00410           double zt = z3 + t*(z4 - z3);
00411           if (testing) {
00412             if (zs > zt)
00413               printf("over");
00414             else if (zs < zt)
00415               printf("under");
00416             else // zs == zt
00417               printf("through");
00418             if (t > 0.99) t = 0.99; // only affects this printf
00419             printf(" segment %5.2f \n", j+t);
00420           }
00421           // negate the over segment
00422           if (zs > zt)
00423             zdowker[zcount - 2] = -zdowker[zcount - 2];
00424           else if (zs < zt)
00425             zdowker[zcount - 1] = -zdowker[zcount - 1];
00426         }
00427       }
00428     } // for j
00429   } // for i
00430 
00431   // the first crossnumber will always be 1, by the way we find the
00432   // intersections.  They will also either all be in even/odd pairs, or it
00433   // is definitely not a knot without some extra closing segment.
00434 
00435   // first pair off and number all the crossing segments from 1 to 2*crossnum
00436   for (i = 0; i < zcount; i++) {
00437     double crosssegment = fabs(zdowker[i]);
00438     int crossnumber = 0;
00439     for (j = 0; j < zcount; j++)
00440       if (crosssegment >= fabs(zdowker[j]))
00441         crossnumber++;
00442     if (zdowker[i] > 0.0)
00443       zorder[i] = crossnumber;
00444     else
00445       zorder[i] = -crossnumber;
00446     if (testing)
00447       printf("%d ", zorder[i]);
00448   }
00449   if (testing)
00450     printf("\n");
00451 
00452   if (zcount == 0) { // no crossings
00453     strcpy(knotstring, "    unknot");
00454     return;
00455   }
00456 
00457   // next convert to Dowker-Thistlethwaite notation, list of even numbers which
00458   // are paired with 1,3,5,... (+ for under, - for over)
00459   for (i = 0; i < zcount; i = i+2) { // zcount is multiple of 2
00460     if (abs(zorder[i])%2 == 0 && abs(zorder[i+1])%2 == 1)
00461       zdk[abs(zorder[i+1])/2] = zorder[i];
00462     else if (abs(zorder[i])%2 == 1 && abs(zorder[i+1])%2 == 0)
00463       zdk[abs(zorder[i])/2] = zorder[i+1];
00464     else { // uh oh, a pair of two odd or two even crossings
00465       if (testing)
00466         printf("both odd or both even, problem\n");
00467       strcpy(knotstring, "odd/even problem");
00468       return;
00469     }
00470   }
00471 
00472   // ok, now create a knot, and send it to our knot finder
00473   int knots[10][MAXCROSS];  //up to 10 knots, should really be 2+MAXCROSS/2?
00474   int ret;
00475   Knot k;
00476   char* knotname;
00477 
00478   knots[0][0] = zcount/2;
00479   knots[0][1] = 1;
00480   if (testing)
00481     printf("%d  %d  ", zcount/2, 1);
00482   for (i = 0; i < zcount/2; i++) {
00483     knots[0][i+2] = zdk[i];
00484     if (testing)
00485       printf("%d ", zdk[i]);
00486   }
00487   if (testing)
00488     printf("\n");
00489     
00490   // send in our knot, get back array of prime factors
00491   ret = k.find_init(knots[0], &knots[0]);
00492   if (testing)
00493     printf("found %d knots\n", ret);
00494   if (ret > 0) {
00495     strcpy(knotstring, "");
00496     for (i = 0 ; i < ret; i++) {
00497       knotname = k.get_knotid(knots[i]);
00498       if (testing)
00499         printf("knot %d: %s : ", i, knotname);
00500       if (i > 0)
00501         strcat(knotstring, "+");
00502       strcat(knotstring, knotname);
00503       if (testing) {
00504         for (j = 0; j < knots[i][0] + 2; j++)
00505           printf("%d ", knots[i][j]);
00506         printf("\n");
00507       }
00508     }
00509   }
00510   else
00511     strcpy(knotstring, "    unknot");
00512 
00513 }
00514 
00515 
00516 
00517 /* function to draw a line for every edge
00518 * using energy to decide color */
00519 void EdgeArray::DrawEdges()
00520 {
00521   /* We really don't care about this energy stuff
00522     double totalenergy, energypercent;
00523     
00524     totalenergy = getEnergy() + nodearray_p->getEnergy();
00525     // loop through all the edges
00526     for (int i = 0; i < numedges; i++) {
00527         // use energy to decide color of each edge
00528         if (totalenergy == 0.0)
00529             energypercent = 0.0;
00530         else
00531             energypercent = (edges[i]->getEnergy())/totalenergy;
00532 
00533         // for if drawing the compression/stretching of edge
00534         // ranges from white (no energy) to red (100% of system's energy)
00535         glColor3d(1.0, (1.0 - energypercent), (1.0 - energypercent));
00536 
00537                 // hack for suture/microsurgery application
00538         if ((getNodeArray()->getObject()->getType() == Object::edges_only) &&
00539             (i < RIGIDNEEDLE))
00540            glColor3d(0.5, 0.5, 0.5);
00541 
00542         // just do the draw
00543         edges[i]->draw();
00544     }
00545   */
00546 
00547   // if we're texturing and drawing a thread, let's add some rope texture
00548   // first, draw quads.  perpendicular lines should be EDGETHRESH in length,
00549   // centered on the edge, bisecting two adjacent edges, and ideally, facing
00550   // the camera.
00551   extern int do_textures;
00552   // even if texture is NULL, the glTexCoord commands don't complain
00553   // so draw the quads for any edge object, if we're doing textures
00554   if (do_textures && getObject()->getType() == Object::edges_only) {
00555     extern int random_flag;
00556     extern int testing_flag;
00557     double EDGETHRESH = getObject()->getEdgeThresh();
00558 
00559     // this does no smoothing, but links up the first and last quads
00560     if (strstr(getObject()->getName(), "ring")) {
00561     Point3D cam_vec, cam_pos;
00562     cam_pos = getCameraPos();
00563     Point3D perp, perp0, perp1, oldperp, v0, v1, pt, u0, u1;
00564     Edge *e0; Edge *e1;
00565     double widthpct = 0.0;  // for the u (width) texture coordinate
00566     glColor4f(1.0, 1.0, 1.0, (getObject()->getDiffuseColor())[3]);
00567     glBegin(GL_QUADS);
00568     // head -- the beginning of the first quad
00569     e1 = getEdge(0);
00570     u1 = e1->UnitDirectionVector();
00571     pt = e1->getNodeLink(0)->p;
00572     // this is perpendicular to edge and vector from camera to edge
00573     cam_vec = pt - cam_pos;
00574     perp1 = u1.Cross(cam_vec);
00575     perp1.Normalize();
00576     // HACK for ring object:
00577     e0 = getEdge(numedges-1);
00578     u0 = e0->UnitDirectionVector();
00579     perp0 = u0.Cross(e0->getNodeLink(0)->p - cam_pos);
00580     perp0.Normalize();
00581     perp = perp0 + perp1;
00582     perp.Normalize();
00583     oldperp = perp;
00584     // end HACK
00585     v0 = pt + 0.5*EDGETHRESH*perp;
00586     v1 = pt - 0.5*EDGETHRESH*perp;
00587     glTexCoord2f(widthpct, 0.0);
00588     glVertex3d(v0.x, v0.y, v0.z);
00589     glTexCoord2f(widthpct, 1.0);
00590     glVertex3d(v1.x, v1.y, v1.z);
00591     //interior
00592     for (int i = 1; i < numedges; i++) {
00593       perp0 = perp1;
00594       e0 = e1;
00595       u0 = u1;
00596       e1 = getEdge(i);
00597       u1 = e1->UnitDirectionVector();
00598       pt = e1->getNodeLink(0)->p;
00599       perp1 = u1.Cross(cam_vec);
00600       perp1.Normalize();
00601       // average of perpendiculars to each edge
00602       perp = perp0 + perp1;
00603       perp.Normalize();
00604       v0 = pt + 0.5*EDGETHRESH*perp;
00605       v1 = pt - 0.5*EDGETHRESH*perp;
00606       // since our texture is 128 x 32, only use 1/4 of it per quad:
00607       widthpct += 0.25;
00608       // end previous quad
00609       glTexCoord2f(widthpct, 1.0);
00610       glVertex3d(v1.x, v1.y, v1.z);
00611       glTexCoord2f(widthpct, 0.0);
00612       glVertex3d(v0.x, v0.y, v0.z);
00613       // and begin next quad
00614       //if (widthpct > 0.99) // eg = 1.0
00615       //  widthpct = 0.0;    // perhaps unnecessary because of GL_REPEAT
00616       glTexCoord2f(widthpct, 0.0);
00617       glVertex3d(v0.x, v0.y, v0.z);
00618       glTexCoord2f(widthpct, 1.0);
00619       glVertex3d(v1.x, v1.y, v1.z);
00620     }
00621     //tail
00622     pt = e1->getNodeLink(1)->p;
00623     perp = oldperp; // HACK for ring object
00624     v0 = pt + 0.5*EDGETHRESH*perp;
00625     v1 = pt - 0.5*EDGETHRESH*perp;
00626     widthpct += 0.25;
00627     glTexCoord2f(widthpct, 1.0);
00628     glVertex3d(v1.x, v1.y, v1.z);
00629     glTexCoord2f(widthpct, 0.0);
00630     glVertex3d(v0.x, v0.y, v0.z);
00631     glEnd();
00632     } // if not smoothing, but matching up first and last quads
00633     // this does parabolic smoothing of adjacent quads
00634     else {
00635     Point3D cam_vec, cam_pos;
00636     cam_pos = getCameraPos();
00637     Point3D perp, oldperp, v0, v1, pt, oldpt, u0, u1;
00638     Edge *e0; Edge *e1;
00639     double widthpct = 0.0;  // for the u (width) texture coordinate
00640     glColor4f(1.0, 1.0, 1.0, (getObject()->getDiffuseColor())[3]);
00641     glBegin(GL_QUADS);
00642     // head -- the beginning of the first quad
00643     e1 = getEdge(0);
00644     u1 = e1->UnitDirectionVector();
00645     pt = e1->getNodeLink(0)->p;
00646     // this is perpendicular to edge and vector from camera to edge
00647     cam_vec = pt - cam_pos;
00648     perp = u1.Cross(cam_vec);
00649     perp.Normalize();
00650     v0 = pt + 0.5*EDGETHRESH*perp;
00651     v1 = pt - 0.5*EDGETHRESH*perp;
00652     extern int needle;
00653     if (needle) { // this draws a pointy needle
00654       //glColor4f(0.5, 0.5, 0.5, (getObject()->getDiffuseColor())[3]);
00655       v0 = pt;
00656       v1 = pt;
00657     }
00658     if (!needle)
00659       glTexCoord2f(widthpct, 0.0);
00660     glVertex3d(v0.x, v0.y, v0.z);
00661     if (!needle)
00662       glTexCoord2f(widthpct, 1.0);
00663     glVertex3d(v1.x, v1.y, v1.z);
00664     // interior
00665     for (int i = 1; i < numedges; i++) {
00666       e0 = e1;
00667       u0 = u1;
00668       e1 = getEdge(i);
00669       u1 = e1->UnitDirectionVector();
00670       // now find the angle between the two edge vectors
00671       double dot = u0.Dot(u1);
00672       double theta = (acos(dot))*(180.0/PI);  // theta between 0 and 180
00673       int k = (int)theta/15; //add an extra quad (per side) per 15 degrees
00674       k = MIN(k, 5);
00675       if ((i == 1) && needle)
00676         k = 0;
00677       for (int j = -k; j <= k; j++) {
00678         oldpt = pt;
00679         oldperp = perp;
00680         double param;
00681         // ok, param is a number in the interval (1-sqrt(2)/2, sqrt(2)/2),
00682         // where .414 is the size of that interval (.707 - .293)
00683         // Why?  Because parametrization A(1-t)(1-t) + B(t)(1-t) + C(t)(t)
00684         // is A/2 + blah for t = .293, and is blah + C/2 for t = .707
00685         // and is A/4 + B/2 + C/4 for param = .5
00686         param = 0.5 + (0.414*j)/(2*k+1);
00687         widthpct = 0.25*e1->getIndex() + 0.25*j/(2*k+1);
00688         pt = (1.0-param)*(1.0-param)*e0->getNodeLink(0)->p +
00689           2.0*param*(1.0-param)*e1->getNodeLink(0)->p +
00690           param*param*e1->getNodeLink(1)->p;
00691         if ((i == 1) && needle) // b/c needle is different length
00692           pt = e1->getNodeLink(0)->p;
00693         cam_vec = pt - cam_pos;
00694         perp = (pt - oldpt).Cross(cam_vec);
00695         perp.Normalize();
00696         v0 = pt + 0.5*EDGETHRESH*perp;
00697         v1 = pt - 0.5*EDGETHRESH*perp;
00698         // if perp flipped direction, unflip it for previous quad:
00699         dot = perp.Dot(oldperp);
00700         theta = (acos(dot))*(180.0/PI);  // theta between 0 and 180
00701         //if (theta > 135.0)   //test to see where we flipped
00702         //glColor3f(1.0,0.0,0.0);
00703         //else
00704         //glColor3f(1.0,1.0,1.0);
00705         if (theta > 135.0) {
00706           v0 = pt - 0.5*EDGETHRESH*perp;
00707           v1 = pt + 0.5*EDGETHRESH*perp;
00708         }
00709         // end previous quad
00710         if (i > 1 || !needle)
00711           glTexCoord2f(widthpct, 1.0);
00712         glVertex3d(v1.x, v1.y, v1.z);
00713         if (i > 1 || !needle)
00714           glTexCoord2f(widthpct, 0.0);
00715         glVertex3d(v0.x, v0.y, v0.z);
00716         // and now reflip perp for next quad if we unflipped it
00717         if (theta > 135.0) {
00718           v0 = pt + 0.5*EDGETHRESH*perp;
00719           v1 = pt - 0.5*EDGETHRESH*perp;
00720         }
00721         // and begin next quad
00722         if (needle && i == 1) // after needle, get rope color correct
00723           glColor4f(1.0, 1.0, 1.0, (getObject()->getDiffuseColor())[3]);
00724         glTexCoord2f(widthpct, 0.0);
00725         glVertex3d(v0.x, v0.y, v0.z);
00726         glTexCoord2f(widthpct, 1.0);
00727         glVertex3d(v1.x, v1.y, v1.z);
00728       } // for j (extra quads for large angles between edges)
00729     } // for i (quad per edge)
00730     // tail -- the end of the last quad
00731     pt = e1->getNodeLink(1)->p;
00732     cam_vec = pt - cam_pos;
00733     perp = u1.Cross(cam_vec);
00734     perp.Normalize();
00735     v0 = pt + 0.5*EDGETHRESH*perp;
00736     v1 = pt - 0.5*EDGETHRESH*perp;
00737     widthpct = 0.25*(e1->getIndex() + 1);
00738     glTexCoord2f(widthpct, 1.0);
00739     glVertex3d(v1.x, v1.y, v1.z);
00740     glTexCoord2f(widthpct, 0.0);
00741     glVertex3d(v0.x, v0.y, v0.z);
00742     glEnd();
00743     } // if smoothing
00744   } // if texturing
00745   else { // no textures, just draw each edge in white or needle color
00746     int microhack = 0;
00747     if (strstr(getObject()->getName(), "thread"))
00748       microhack = 1;
00749     for (int i = 0; i < numedges; i++) {
00750       glColor3d(1.0, 1.0, 1.0);
00751       // hack for suture/microsurgery application
00752       if (microhack && (i < RIGIDNEEDLE))
00753         glColor3d(0.5, 0.5, 0.5);
00754       edges[i]->draw();
00755     }
00756   }
00757 }
00758 
00759 void EdgeArray::drawover(double scale)
00760 {
00761     // loop through all the edges
00762     for (int i = 0; i < numedges; i++) {
00763         edges[i]->drawover(scale);
00764     }
00765 }
00766 
00767 void EdgeArray::drawinitial()
00768 {
00769     // loop through all the edges
00770     for (int i = 0; i < numedges; i++) {
00771         // draw the initial configuration in gray 
00772         edges[i]->drawInitial();
00773     }
00774 }
00775 
00776 void EdgeArray::drawlabels(float offset)
00777 {
00778     // loop through all the edges
00779     for (int i = 0; i < numedges; i++) {
00780         // draw the labels
00781         edges[i]->drawlabel(offset);
00782     }
00783 }
00784 
00785 // this sets the spring constant for every edge to be value
00786 void EdgeArray::setSpringConstants(double value, int restLengthScale)
00787 {
00788   for (int i = 0; i < numedges; i++) {
00789     edges[i]->setSpringConstant(value, restLengthScale);
00790   }
00791 }
00792 
00793 // this sets the damp constant for every edge to be value
00794 // NOTE: not using dampConstant usually, using velocityDampConstant in node
00795 void EdgeArray::setDampConstants(double value)
00796 {
00797     for (int i = 0; i < numedges; i++) {
00798         edges[i]->setDampConstant(value);
00799     }
00800 }
00801 
00802 // function to calculate total energy of the edges
00803 double EdgeArray::getEnergy(void)
00804 {
00805     int i;
00806     double total = 0.0;
00807     for (i = 0; i < numedges; i++) 
00808         total += edges[i]->getEnergy();
00809     
00810     return total;
00811 }
00812 
00813 void EdgeArray::DeleteEdge(int index)
00814 {
00815     if (debug) cerr << "EdgeArray::DeleteEdge(" << index << ")\n";
00816     
00817     // sanity check
00818     if (index < 0) return;
00819     
00820     // delete the one we've got
00821     delete edges[index];
00822     
00823     // pack the rest all down
00824     for (int i=index; i<numedges-1; i++)
00825         edges[i] = edges[i+1];
00826     
00827     // and decrement the number of edges
00828     numedges--;
00829 }
00830 
00831 void EdgeArray::DeleteEdge(Edge* e)
00832 {
00833     if (debug) cerr << "EdgeArray::DeleteEdge(" << e << ")\n";
00834     
00835     // get index of edge
00836     int index = getIndex(e);
00837     
00838     // and delete it
00839     DeleteEdge(index);
00840 }
00841 
00842 void EdgeArray::EraseEdge(Edge* e)
00843 {
00844     Edge *tempEdge = e;
00845     Node *node0 = e->getNodeLink(0);
00846     
00847     node0->deleteEdgeLink( e );
00848     e->getOtherNode(node0)->deleteEdgeLink( e );
00849     DeleteEdge( tempEdge );
00850 }
00851 
00852 void EdgeArray::DeleteFacelessEdges()
00853 {
00854     int open_slot = 0;
00855     for (int i=0; i<numedges; i++) {
00856         if (edges[i]->numFaceLinks() <= 0) 
00857             delete edges[i];
00858         else edges[open_slot++] = edges[i];
00859     }
00860     numedges = open_slot;
00861 }
00862 
00863 void EdgeArray::DeleteAllEdges()
00864 {
00865     // turns out all we have to do is reset the number
00866     numedges = 0;
00867 }
00868 
00869 
00870 void EdgeArray::SanityCheck()
00871 {
00872     string s("");
00873     
00874     // check our stuff
00875     if (numedges < 0) s += "numedges < 0!";
00876     if (numedges > maxedges) s += "numedges > maxedges!";
00877     if (maxedges < 0) s += "maxedges < 0!";
00878     if (!edges) s += "edges is NULL!";
00879     if (!nodearray_p) s += "nodearray_p is NULL!";
00880     
00881     // if there's a problem, print it out
00882     //s << ends;
00883     if (s.size() > 0)
00884         cerr << "EdgeArray: INSANE: " << s.c_str() << endl;
00885     
00886     // check all the edges
00887     for (int i=0; i<numedges; i++)
00888         edges[i]->SanityCheck(this);
00889 }
00890 
00891 void EdgeArray::Cleanup()
00892 {
00893     // check all the edges
00894     for (int i=0; i<numedges; i++) {
00895         Edge* e = getEdge(i);
00896         int s = e->SanityCheck(this);
00897         if (!s) EraseEdge(e);
00898     }
00899 }
00900 
00901 int EdgeArray::CompressDuplicateEdges()
00902 {
00903     int num_dup_edges = 0;
00904     
00905     for (int i=0; i<getNumEdges(); i++) {
00906         Edge* e = getEdge(i);
00907         Node* n0 = e->getNodeLink(0);
00908         Node* n1 = e->getNodeLink(1);
00909         
00910         for (int j=0; j<getNumEdges(); j++) {
00911             Edge* other_e = getEdge(j);
00912             
00913             // if is a duplicate (between same nodes as edge e)
00914             if (other_e->hasNodeLink(n0) && other_e->hasNodeLink(n1)) {
00915                 // move our faces to them
00916                 // (note: if we have a really wacky geometry, then each edge could
00917                 // have duplicate faces and we'd be moving too many faces over,
00918                 // but then the mesh is so bad that this is okay to do anyway)
00919                 for (int k=0; k<other_e->numFaceLinks(); k++) {
00920                     Face* f = other_e->getFaceLink(k);
00921                     if (!e->hasFaceLink(f)) e->addFaceLink(f);
00922                 }
00923                 
00924                 // and delete it
00925                 DeleteEdge(j);
00926                 
00927                 // and keep counter
00928                 num_dup_edges++;
00929             }
00930         }
00931     }
00932     
00933     // and return how many we squashed out
00934     return(num_dup_edges);
00935 }
00936 

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