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

Go to the documentation of this file.
00001 /* $Id: edge.cpp,v 1.59 2006/01/06 19:28:11 craig Exp $ */
00002 #include "edge.h"
00003 #include "node.h"
00004 #include "face.h"
00005 #include "object.h"
00006 #include "point3d.h"
00007 #include "nodearray.h"
00008 #include "edgearray.h"
00009 #include "rasterfont.h"
00010 #include <stdio.h>
00011 #include <math.h>
00012 
00013 #ifdef _WIN32
00014 #include <windows.h>
00015 #endif
00016 
00017 #ifdef __APPLE__
00018 #include <OpenGL/gl.h>
00019 #else
00020 #include <GL/gl.h>
00021 #endif // __APPLE__
00022 
00023 const char* Edge::rcsid = "@(#) $Id: edge.cpp,v 1.59 2006/01/06 19:28:11 craig Exp $ $Copyright: (c)2001 National Biocomputation Center, Stanford University $";
00024 
00025 
00026 int Edge::debug = 0;
00027 
00028 Edge::Edge()
00029 {
00030     node[0] = node[1] = NULL;
00031     splitNode[0] = splitNode[1] = NULL;
00032     marker = -1.0;
00033     boundingsphere = NULL;
00034 }
00035 
00036 Edge::~Edge()
00037 {
00038     node[0] = node[1] = NULL;
00039 }
00040 
00041 // this fills in values for an Edge from the edge data file
00042 int Edge::init(NodeArray* nodearray_p, EdgeArray* edgearray_p_in, 
00043                char *initString)
00044 {
00045     int n1, n2, index;
00046     double restLength_given, springConstant_given, dampConstant_given;
00047     
00048     // parse string
00049     if (sscanf(initString, "%d %d %d %lf %lf %lf", &index, &n1, &n2,
00050         &restLength_given, &springConstant_given, &dampConstant_given) !=6){ 
00051         printf("Wrong number of arguments in edge data line\n");
00052         return 0;
00053     }
00054     
00055     // call the main init routine
00056     int s = init(nodearray_p, edgearray_p_in, n1, n2, restLength_given, 
00057                springConstant_given, dampConstant_given);
00058     return(s);
00059 }
00060 
00061 // this fills in values for an Edge from the given data
00062 int Edge::init(NodeArray* nodearray_p, EdgeArray* edgearray_p_in,
00063                int i0, int i1, double restLength_in, 
00064                double springConstant_in, double dampConstant_in)
00065 {
00066     // check if node indices are in our node array
00067     int numnodes = nodearray_p->getNumNodes();
00068     if ((i0 < 0) || (i1 < 0) || (i0 > numnodes) || (i1 > numnodes)) {
00069         printf("Node numbers in edge data line are out of bounds\n");
00070         return(0);
00071     }
00072     else if (i0 == i1) {
00073         printf("Edge can't connect a node to itself\n");
00074         return(0);
00075     }
00076     
00077     // get node ptrs from the given indices
00078     Node* n0 = nodearray_p->getNode(i0);
00079     Node* n1 = nodearray_p->getNode(i1);
00080     
00081     // call the real init
00082     int s = init(nodearray_p, edgearray_p, n0, n1, restLength_in, 
00083                springConstant_in, dampConstant_in);
00084     
00085     // and return its value
00086     return(s);
00087 }
00088 
00089 // this fills in values for an Edge from the given data
00090 int Edge::init(NodeArray* nodearray_p, EdgeArray* edgearray_p_in,
00091                Node* n0, Node* n1, double restLength_in, 
00092                double springConstant_in, double dampConstant_in)
00093 {
00094     // set private vars
00095     edgearray_p = edgearray_p_in;
00096     node[0] = n0;
00097     node[1] = n1;
00098     
00099     // add our edge to the nodes
00100     node[0]->addEdgeLink(this);  // then update the edge arrays for these Nodes
00101     node[1]->addEdgeLink(this);
00102     
00103     // calculate the restlength of the spring.
00104     switch( (int) restLength_in ) {
00105     case -1: restLength = this->getLength(); break;
00106     case -2: restLength = this->getLength() * 0.95; break;
00107     case -3: restLength = this->getLength() * 1.07; break;
00108     default: restLength = restLength_in; break;
00109     }
00110     
00111     springConstant = springConstant_in;
00112     dampConstant = dampConstant_in;
00113     
00114     return (1);
00115 }
00116 
00117 
00118 /* this is called three times for each Face in the meshfile, once for each of
00119 * the edges it contains */
00120 // Note: Really only need the faces to get the normals to get the angle for
00121 //                      torsion processing (which we don't use anymore)
00122 void Edge::addFaceLink(Face *f)
00123 {
00124     if (debug)
00125     cout << "\nEdge " << getIndex() << " ::addFaceLink(" << f->getIndex() << ")\n";
00126   face.Append(f);
00127     
00128 #ifdef TORSION
00129     // handle torsion/initial angles
00130     if (face.NumElements()) {
00131         /* for now, calculate the initial angle between the faces here */
00132         // but we need normals to do that:
00133         face[0]->computenormal();
00134         face[1]->computenormal();
00135         init_angle = getAngle();
00136     }
00137 #endif
00138 }
00139 
00140 void Edge::addTetraLink(Tetra *t)
00141 {
00142   if (debug)
00143     cerr << "\nEdge " << getIndex() << " ::addTetraLink(" << t->getIndex() << ")\n";
00144   tetra.Append(t);
00145 }
00146 
00147 void Edge::deleteFaceLink(Face* f)
00148 {
00149   if (debug)
00150     cout << "\nEdge " << getIndex() << " ::deleteFaceLink(" << f->getIndex() << ")\n";
00151 
00152   face.DeleteItem(f);
00153         if (debug) 
00154           cout << "ended up with " << face.NumElements() << " face left\n";
00155 }
00156 
00157 void Edge::deleteTetraLink(Tetra *t)
00158 {
00159   if (debug)
00160     cout << "\nEdge " << getIndex() << " ::deleteTetraLink(" << t->getIndex() << ")\n";
00161 
00162   tetra.DeleteItem(t);
00163         if (debug) 
00164           cout << "ended up with " << tetra.NumElements() << " tetra left\n";
00165 }
00166 
00167 void Edge::replaceNodeLink(Node* old_node, Node* new_node)
00168 {
00169     for (int i=0; i<2; i++) {
00170         if (node[i] == old_node) node[i] = new_node;
00171     }
00172 }
00173 
00174 int Edge::getIndex()
00175 { return(edgearray_p->getIndex(this)); }
00176 
00177 /* this calculates the angle between this Edge's 2 adjacent faces.
00178 * Normals must be consistent (hopefully outward facing), the angle is then
00179 * starting at one face, in the direction of the normal, to the other face*/
00180 double Edge::getAngle(void)
00181 {
00182     Point3D norm1, norm2, vec;
00183     double dot, theta, dot2, retangle;
00184     if (face.NumElements()!= 2) { // to do: caller should check this?
00185         printf("called getAngle with face.NumElements() != 2, bad \n");
00186         return (-1);
00187     }
00188     // get the normals of the adjacent faces (they are unit length)
00189     norm1 = face[0]->getNormal();
00190     norm2 = face[1]->getNormal();
00191     dot = norm1.Dot(norm2);
00192     theta = (acos(dot))*(180.0/PI);
00193     /* theta is now the angle between the normals.  actual angle between the
00194     * faces is 180 +- theta.  decide by taking a 3rd vector, starting at this
00195     * edge, and going into face1, and dotting with face0's normal, norm1 */
00196     Node *n = face[1]->getThirdNode(node[0], node[1]);
00197     // find this vector in face1 by going from node to n
00198     // don't care about magnitude, just need sign of dot product
00199     vec = n->p - node[0]->p;
00200     dot2 = norm1.Dot(vec);
00201     if (dot2 < 0.0)
00202         retangle = 180.0 + theta;
00203     else
00204         retangle = 180.0 - theta;
00205     
00206     if (debug)
00207         printf("edge %d normal angle %f face angle %f \n", 
00208         getIndex(), theta, retangle);
00209     return (retangle);
00210 }
00211 
00212 // Spring force with FULL damping
00213 void Edge::ComputeSpringForceFullDamp(void)
00214 {       
00215         // Uses endpoints of the edge and spring characteristics to find
00216         // the force between the nodes.
00217         // Result computed is force from first to second node of the edge.
00218         
00219         // This is directional.  Computes the force from the first to the 2nd node.
00220         
00221         /* calculate vector forces as we should:
00222         * magnitude f = -k*delta_position
00223         * direction f = spring_unit = diff/||diff|| */
00224         Point3D diff = node[1]->p - node[0]->p;
00225         
00226         // Any way to avoid the square root computation?
00227         double normSquared = diff.Squared();
00228         
00229         // ??? Can we remove this test - will the two points ever be at the same location?
00230         if (normSquared > 0.0) {
00231                 Point3D vdiff = node[1]->v - node[0]->v;
00232                 double velocityDotSpring = vdiff.Dot(diff);
00233                 
00234                 double springLength = sqrt(normSquared);
00235                 double deltaPosition = springLength - restLength;
00236                 
00237                 double totalDampMagnitude = 
00238                         (dampConstant * velocityDotSpring / normSquared);
00239                 
00240                 force = -((springConstant * deltaPosition / springLength) + totalDampMagnitude) * diff;
00241         }
00242         else {
00243                 force = Point3D(0.0, 0.0, 0.0);
00244         }
00245 }
00246 
00247 // Spring force with REL damping
00248 void Edge::ComputeSpringForceRelDamp(void)
00249 {
00250         // Uses endpoints of the edge and spring characteristics to find
00251         // the force between the nodes.
00252         // Result computed is force from first to second node of the edge.
00253         
00254         // This is directional.  Computes the force from the first to the 2nd node.
00255         
00256         /* calculate vector forces as we should:
00257         * magnitude f = -k*delta_position
00258         * direction f = spring_unit = diff/||diff|| */
00259         Point3D diff = node[1]->p - node[0]->p;
00260         
00261         // Any way to avoid the square root computation?
00262         double normSquared = diff.Squared();
00263         double springLength = sqrt(normSquared);
00264         double deltaPosition = springLength - restLength;
00265 
00266         // REL
00267         /* damping based on relative velocity for every Edge:
00268         * vxdiff:relative_velocity::fx:f
00269         * and f = -c*relative_velocity
00270         * so fx = -c*vxdiff */
00271         Point3D vdiff = node[1]->v - node[0]->v;
00272 
00273         force = -(springConstant * deltaPosition / springLength) * diff - dampConstant * vdiff;
00274 }
00275 
00276 // Computes the force on the vector from the first point to the second point,
00277 // based on linear spring characteristics and damping.
00278 // Note that the switch for dampingType slows this down.
00279 // Perhaps make 3 specific versions to avoid the switch.
00280 // Added 2-Nov-2005, cwc.
00281 
00282 void Edge::ComputeSpringForce(int dampingType)
00283 {
00284         // Uses endpoints of the edge and spring characteristics to find
00285         // the force between the nodes.
00286         // Result computed is force from first to second node of the edge.
00287         
00288         // Compute the force from the first to the 2nd node.
00289         
00290         /* calculate vector forces as we should:
00291         * magnitude f = -k*delta_position
00292         * direction f = spring_unit = diff/||diff|| */
00293         Point3D diff = node[1]->p - node[0]->p;
00294         
00295         // Any way to avoid the square root computation?
00296         double normSquared = diff.Squared();
00297         double springLength = sqrt(normSquared);
00298         double deltaPosition = springLength - restLength;
00299 
00300         // Note that ABS case is computed per node...
00301         // And NONE doesn't use any damping.
00302         switch (dampingType) {
00303         case ABS:
00304         case NONE:
00305                 force = -(springConstant * deltaPosition / springLength) * diff;
00306                 break;
00307         
00308         case FULL:
00309                 // FULL
00310                 /* damping based on relative velocity for every Edge, *BUT*
00311                 * only in the direction of the spring:
00312                 * f = -c*(relative velocity component along spring)
00313                 *   = -c*(relative_velocity dot spring_unit)*spring_unit
00314                 * relative_velocity = vdiff
00315                 * spring_unit = diff/||diff||
00316                 * f = -c*(vdiff dot diff)*diff/||diff||^2 */
00317                 
00318                 if (normSquared > 0.0) {
00319                         Point3D vdiff = node[1]->v - node[0]->v;
00320                         double velocityDotSpring = vdiff.Dot(diff);             // The fractional velocity along position vector.
00321                         
00322                         force = -(springConstant * deltaPosition / springLength + 
00323                                 dampConstant * velocityDotSpring / normSquared) * diff;
00324                         
00325                 }
00326                 break;
00327                 
00328         case REL:
00329                 // REL
00330                 /* damping based on relative velocity for every Edge:
00331                 * vxdiff:relative_velocity::fx:f
00332                 * and f = -c*relative_velocity
00333                 * so fx = -c*vxdiff */
00334                 Point3D vdiff = node[1]->v - node[0]->v;
00335                 force = -(springConstant * deltaPosition / springLength) * diff;
00336                 force -= dampConstant*vdiff;
00337                 break;
00338                 
00339 
00340         }
00341         
00342 }
00343 
00344 void Edge::ComputeSpringForceNonlinear(int dampingType)
00345 {
00346         // Uses endpoints of the edge and spring characteristics to find
00347         // the force between the nodes.
00348         // Result computed is force from first to second node of the edge.
00349         
00350         // Compute the force from the first to the 2nd node.
00351         
00352         /* calculate vector forces as we should:
00353         * magnitude f = -k*delta_position
00354         * direction f = spring_unit = diff/||diff|| */
00355         Point3D diff = node[1]->p - node[0]->p;
00356         
00357         // Any way to avoid the square root computation?
00358         double normSquared = diff.Squared();
00359         double springLength = sqrt(normSquared);
00360         double deltaPosition = springLength - restLength;
00361 
00362         if (normSquared <= 0.0) {
00363                 // There's a chance that the nodes are very close.
00364                 force.x = force.y = force.z = 0.0;
00365                 return;
00366         }
00367 
00368         double nonlinear_factor = 1.0;
00369         {
00370                 double ratio = springLength/restLength;
00371                 if (ratio < 1.0 && ratio != 0.0)
00372                         // Force increases for compression too!
00373                         ratio = 1/ratio;
00374                 if (ratio < 2)
00375                         ; // between 1/2 and 2 times normal length do nothing
00376                 else if (ratio < 4)
00377                         nonlinear_factor = 1.2;
00378                 else if (ratio < 8)
00379                         nonlinear_factor = 1.4;
00380                 else if (ratio >= 8)
00381                         nonlinear_factor = 1.6;
00382         }
00383 
00384         // This is the force computation, based on the type of damping.
00385 
00386         // Note that ABS case is computed per node...
00387         switch (dampingType) {
00388 
00389         case FULL:
00390                 {
00391                         // FULL
00392                         /* damping based on relative velocity for every Edge, *BUT*
00393                         * only in the direction of the spring:
00394                         * f = -c*(relative velocity component along spring)
00395                         *   = -c*(relative_velocity dot spring_unit)*spring_unit
00396                         * relative_velocity = vdiff
00397                         * spring_unit = diff/||diff||
00398                         * f = -c*(vdiff dot diff)*diff/||diff||^2 */
00399                         
00400                         Point3D vdiff = node[1]->v - node[0]->v;
00401                         
00402                         double velocityDotSpring = vdiff.Dot(diff);
00403                         
00404                         double totalDampMagnitude = (dampConstant * velocityDotSpring / normSquared);
00405                         
00406                         // Combine these to reduce multiplications by the diff vector.
00407                         force = -(nonlinear_factor * springConstant * deltaPosition / springLength + totalDampMagnitude) * diff;
00408                 }
00409                 break;
00410                 
00411         case REL:
00412                 {
00413                         // REL
00414                         /* damping based on relative velocity for every Edge:
00415                         * vxdiff:relative_velocity::fx:f
00416                         * and f = -c*relative_velocity
00417                         * so fx = -c*vxdiff */
00418                         Point3D vdiff = node[1]->v - node[0]->v;
00419                         force = -(nonlinear_factor * springConstant * deltaPosition / springLength) * diff;
00420                         force -= dampConstant*vdiff;
00421                 }
00422                 break;
00423 
00424         case ABS:
00425         case NONE:
00426         default:
00427                 {
00428                         // Just the simple force computation
00429                         force = -(nonlinear_factor * springConstant * deltaPosition / springLength) * diff;
00430                 }
00431                 break;
00432 
00433         }
00434         
00435 }
00436 
00437 /* function to calculate the torsion force between face0 and face1, and apply
00438 * this force to the exterior nodes of those faces */
00439 void Edge::addTorsion(void)
00440 {
00441     if (face.NumElements() == 2) {
00442         // for now we'll compute the normals here
00443         face[0]->computenormal();
00444         face[1]->computenormal();
00445         // if this is positive, apply force in direction of normal, else opposite
00446         double anglediff = getAngle() - init_angle;
00447         Point3D force1 = (anglediff*TORSION_FORCE)*(face[0]->getNormal());
00448         Point3D force2 = (anglediff*TORSION_FORCE)*(face[1]->getNormal());
00449         Node *n1 = face[0]->getThirdNode(node[0], node[1]);
00450         Node *n2 = face[1]->getThirdNode(node[0], node[1]);
00451         n1->addForce(force1);
00452         n2->addForce(force2);
00453     }
00454 }
00455 
00456 /* This function returns the potential energy of this Edge (spring) 
00457 * E = 0.5*k*x^2 where k is the spring constant, x is the displacement from
00458 * resting position, E calculated by integrating F = k*x from 0 to x
00459 */
00460 double Edge::getEnergy(void)
00461 {
00462     double length = getLength();
00463     double displacement = fabs(length - restLength);
00464     double energy = 0.5*springConstant*displacement*displacement;
00465     return (energy);
00466 }
00467 
00468 
00469 Point3D Edge::UnitDirectionVector(void)
00470 {
00471     Point3D vect = getNodeLink(1)->p - getNodeLink(0)->p;
00472     vect.Normalize();
00473     return vect;
00474 }
00475 
00476 // distance between edge and point, as well as param for near point on edge
00477 // if no near pointer is sent in, it will create a dummy value
00478 double Edge::EdgeDistanceToPoint(Point3D pt, double *near1)
00479 {
00480     Point3D dirVect;
00481     Node *n0, *n1;
00482     double t;
00483     double dummy;
00484     if (near1 == NULL)
00485       near1 = &dummy;
00486     *near1 = 0.0;
00487     
00488     n0 = getNodeLink(0);
00489     n1 = getNodeLink(1);
00490     dirVect = UnitDirectionVector();
00491     
00492     /* project n0 to pt vector onto this edge, it actually lies on this edge
00493     * if projected distance is between 0 and this edge's length */
00494     t = dirVect.Dot(pt - n0->p);
00495    
00496     if( t <= 0 ) {// closest to node 0
00497       // value of near1 is already 0.0
00498       return( (pt - n0->p).Length() );
00499     }
00500     double length = getLength();
00501     if( t >= length ) {// closest to node 1
00502       *near1 = 1.0;
00503       return( (pt - n1->p).Length() );
00504     }
00505     //closest to some point on edge, figure out its parameter in (0,1)
00506     if (length != 0.0)
00507       *near1 = t/length; // t can range from 0 to edge length in this case
00508     return((pt - n0->p - t*dirVect).Length());
00509 }
00510 
00511 // returns distance between 2 edges, as well as near point on each edge
00512 // if no near pointer is set in, it will create dummy values
00513 double Edge::EdgeDistanceToEdge(Edge* e2, double *near1, double *near2)
00514 {
00515     Edge *e1 = this;
00516     double dummy1;
00517     double dummy2;
00518     if (near1 == NULL) {
00519       near1 = &dummy1;
00520       near2 = &dummy2;
00521     }
00522     /* get lines containing e1 and e2, then use Goldman's Gem (vol 1, p 304)
00523     * to get the points of closest approach.  if these points are on the
00524     * edges, we're done, otherwise I think the closest distance must involve
00525     * one of the 4 endpoints */
00526     // L1(t) = p1 + v1*t, L2(s) = p2 + v2*s, v1 and v2 unit direction vectors
00527     Point3D p1 = e1->getNodeLink(0)->p;
00528     Point3D p2 = e2->getNodeLink(0)->p;
00529     Point3D v1 = e1->UnitDirectionVector();
00530     Point3D v2 = e2->UnitDirectionVector();
00531     Point3D p2minusp1 = p2 - p1;
00532     Point3D v1crossv2 = v1.Cross(v2);
00533     double denom = v1crossv2.Squared();
00534     
00535     if (denom != 0.0) {  //not parallel, there is a point of closest approach
00536         double t = (p2minusp1.Determinant(v2, v1crossv2))/denom;
00537         double s = (p2minusp1.Determinant(v1, v1crossv2))/denom;
00538         if (t > 0 && s > 0 && t < e1->getLength() && s < e2->getLength()) {
00539             // point of closest approach is on the segments, return length
00540             *near1 = t/(e1->getLength());
00541             *near2 = s/(e2->getLength());
00542             return (((p1 + v1*t) - (p2 + v2*s)).Length());
00543         }
00544     }
00545   // find the distance from each endpoint to the other segment, return min
00546   double nearA, nearB, nearC, nearD;
00547   double d1 = e1->EdgeDistanceToPoint(p2, &nearA);
00548   double d2 = e1->EdgeDistanceToPoint(e2->getNodeLink(1)->p, &nearB);
00549   double d3 = e2->EdgeDistanceToPoint(p1, &nearC);
00550   double d4 = e2->EdgeDistanceToPoint(e1->getNodeLink(1)->p, &nearD);
00551 
00552   double min12 = MIN(d1, d2);
00553   double min34 = MIN(d3, d4);
00554   double min = MIN(min12, min34);
00555   
00556   if (d1 == min) {
00557     *near1 = nearA;
00558     *near2 = 0.0;
00559   }
00560   else if (d2 == min) {
00561     *near1 = nearB;
00562     *near2 = 1.0;
00563   }
00564   else if (d3 == min) {
00565     *near1 = 0.0;
00566     *near2 = nearC;
00567   }
00568   else if (d4 == min) {
00569     *near1 = 1.0;
00570     *near2 = nearD;
00571   }
00572   else // nothing is the minimum???
00573     printf("Um, problem in EdgeDistanceToEdge\n");
00574 
00575   return (min);
00576 }
00577 
00578 // returns the distance between an edge and a face, as well as the
00579 //      near points on each.
00580 // ? does _not_ check for intersection, if they are intersecting, then the
00581 //      motion limit has failed, and it's too late to deal with ?
00582 double Edge::EdgeDistanceToFaceNoIntersect(Face* f, double *near1, 
00583                                            Point3D *nearpt)
00584 {
00585   // 3 cases:
00586   // 1. This edge intersects face
00587   // 2. One of this edge's 2 endpoints closest to face
00588   // 3. This edge closest to one of face's 3 edges
00589   // We ignore 1., get minimum value from 2. and 3.
00590   // moreover, only care about 2. if endpoint projects inside face
00591 
00592   // early cutout?: if either endpoint is too far from face
00593 
00594   Point3D nearpt1, nearpt2;
00595   double nearA1, nearA2, nearB1, nearB2, nearC1, nearC2;
00596   Edge *fe0 = f->getEdgeLink(0);
00597   Edge *fe1 = f->getEdgeLink(1);
00598   Edge *fe2 = f->getEdgeLink(2);
00599 
00600   double d1 = f->FaceDistanceToPoint(getNodeLink(0)->p, 1, &nearpt1);
00601   double d2 = f->FaceDistanceToPoint(getNodeLink(1)->p, 1, &nearpt2);
00602   double d3 = EdgeDistanceToEdge(fe0, &nearA1, &nearA2);
00603   double d4 = EdgeDistanceToEdge(fe1, &nearB1, &nearB2);
00604   double d5 = EdgeDistanceToEdge(fe2, &nearC1, &nearC2);
00605 
00606   double min12 = MIN(d1, d2);
00607   double min34 = MIN(d3, d4);
00608   double min1234 = MIN(min12, min34);
00609   double min = MIN(min1234, d5);
00610 
00611   // near1 is param of edge near point, nearpt is face near point
00612   if (d1 == min) {
00613     *near1 = 0.0;
00614     *nearpt = nearpt1;
00615   }
00616   else if (d2 == min) {
00617     *near1 = 1.0;
00618     *nearpt = nearpt2;
00619   }
00620   else if (d3 == min) {
00621     *near1 = nearA1;
00622     *nearpt = fe0->getNodeLink(0)->p + nearA2*
00623       (fe0->getNodeLink(1)->p - fe0->getNodeLink(0)->p);
00624   }
00625   else if (d4 == min) {
00626     *near1 = nearB1;
00627     *nearpt = fe1->getNodeLink(0)->p + nearB2*
00628       (fe1->getNodeLink(1)->p - fe1->getNodeLink(0)->p);
00629   }
00630   else if (d5 == min) {
00631     *near1 = nearC1;
00632     *nearpt = fe2->getNodeLink(0)->p + nearC2*
00633       (fe2->getNodeLink(1)->p - fe2->getNodeLink(0)->p);
00634   }
00635   else // nothing is the minimum???
00636     printf("Um, problem in EdgeDistanceToFaceNoIntersect\n");
00637 
00638   return (min);
00639 }
00640 
00641 void Edge::draw()
00642 {
00643     Node* n1 = getNodeLink(0);
00644     Node* n2 = getNodeLink(1);
00645     
00646     // needle edges are now handled in edgearray::DrawEdges
00647     
00648     if (marker >= 0.0) {
00649       // mark closest points of "colliding" edges in red
00650       glColor3d(1.0, 0.0, 0.0);
00651       glPointSize(5.0);
00652       Point3D pt = n1->p + marker*(n2->p - n1->p);
00653       glBegin(GL_POINTS);
00654       glVertex3d(pt.x, pt.y, pt.z);
00655       glEnd();
00656       // mark colliding edges as green
00657       glColor3d(0.0, 1.0, 0.0);
00658     }
00659     
00660     glLineWidth(2.0); // thread (if not textured) shows up better if wider
00661     glBegin(GL_LINES);
00662     n1->draw(0, 0, 0);
00663     n2->draw(0, 0, 0);
00664     glEnd();
00665     glLineWidth(1.0);
00666 }
00667 
00668 void Edge::drawover(double scale)
00669 {
00670     // draw differently based on face.NumElements()
00671     switch (face.NumElements()) {
00672     case 0: glColor3d(1.0, 1.0, 0.0); break;    // yellow
00673     case 1: glColor3d(0.0, 1.0, 0.0); break;    // green
00674     case 2: glColor3d(0.0, 0.0, 0.0); break;    // black
00675     }
00676     
00677     Node* n1 = getNodeLink(0);
00678     Node* n2 = getNodeLink(1);
00679     glBegin(GL_LINES);
00680     n1->drawover(scale);
00681     n2->drawover(scale);
00682     glEnd();
00683 }
00684 
00685 void Edge::drawInitial()
00686 {
00687     Node* n1 = getNodeLink(0);
00688     Node* n2 = getNodeLink(1);
00689     glColor3f(0.5, 0.5, 0.5);
00690     glBegin(GL_LINES);
00691     n1->drawinitial();
00692     n2->drawinitial();
00693     glEnd();
00694 }
00695 
00696 // make a label containing the face num
00697 void Edge::drawlabel(float offset)
00698 {
00699     extern RasterFont* font_p;
00700     char s[20]; sprintf(s, "%d", getIndex());
00701     Node* n1 = getNodeLink(0);
00702     Node* n2 = getNodeLink(1);
00703     Point3D center = (n1->p + n2->p)/2.0;
00704     
00705     Point3D avg_normal = (n1->getNormal() + n2->getNormal())/2.0;
00706     Point3D ll = center + offset*avg_normal;
00707     
00708     glBegin(GL_LINES);
00709     glVertex3d(center.x, center.y, center.z);
00710     glVertex3d(ll.x, ll.y, ll.z);
00711     glEnd();
00712     
00713     font_p->printString(s, ll.x,ll.y,ll.z);
00714 }
00715 
00716 // determines whether the plane ax+by+cz+d=0 crosses the edge [P1,P2]. If yes, 
00717 // the function returns 1 (and the point of intersection is determined), else 0
00718 int Edge::crossesPlane(double a, double b, double c, double d, 
00719                        Point3D *intersection_p)
00720 {
00721     Point3D P1 = getNodeLink(0)->p;
00722     Point3D P2 = getNodeLink(1)->p;
00723     double alpha, t;
00724     
00725     alpha = a * (P1.x - P2.x) + b * (P1.y - P2.y) + c * (P1.z - P2.z);
00726     if(alpha == 0) return 0;
00727     
00728     t = -(a * P2.x + b * P2.y + c * P2.z + d) / alpha;
00729     if ((t < 0) || (t > 1)) return 0;
00730     
00731     if (intersection_p) {
00732         intersection_p->x = (P1.x - P2.x) * t + P2.x;
00733         intersection_p->y = (P1.y - P2.y) * t + P2.y;
00734         intersection_p->z = (P1.z - P2.z) * t + P2.z;
00735     }
00736     
00737     return 1;
00738 }
00739 int Edge::crossesPlane(Point3D p1, Point3D p2, Point3D p3, Point3D *intPt)
00740 {
00741         int intersects = 0;
00742         double a,b,c,d;
00743                 a = p1.y*(p2.z-p3.z) + p2.y*(p3.z - p1.z) + p3.y*(p1.z - p2.z);
00744                 b = p1.z*(p2.x-p3.x) + p2.z*(p3.x - p1.x) + p3.z*(p1.x - p2.x);
00745                 c = p1.x*(p2.y-p3.y) + p2.x*(p3.y - p1.y) + p3.x*(p1.y - p2.y);
00746                 d = -(p1.x*(p2.y*p3.z - p2.z*p3.y) +
00747                                         p2.x*(p3.y*p1.z - p3.z*p1.y) + 
00748                                         p3.x*(p1.y*p2.z - p1.z*p2.y));
00749         intersects = crossesPlane(a,b,c,d,intPt);
00750         return intersects;
00751 }
00752 
00753 int Edge::SanityCheck(EdgeArray* real_ea_p)
00754 {
00755     char s[1024]; s[0] = '\0';
00756     char tmps[1024]; tmps[0] = '\0';
00757     
00758     // look at my local stuff
00759     int my_index = -1;
00760     if (!edgearray_p) strcat(s,"edgearray_p is NULL!");
00761     if (edgearray_p != real_ea_p) strcat(s,"edgearray_p is incorrect!");
00762     else {
00763         my_index = getIndex();
00764         if (my_index < 0) { sprintf(tmps, "getIndex() = %d\n", my_index); strcat(s, tmps); }
00765     }
00766     
00767     // don't care about init_angle anymore (no more torsion)
00768     if (restLength <= 0) strcat(s, "restLength <= 0!");
00769     if (springConstant <= 0) strcat(s, "springConstant <= 0!");
00770     if (dampConstant <= 0) strcat(s, "dampConstant <= 0!");
00771     if (face.NumElements() < 0) strcat(s, "face.NumElements() < 0!");
00772     if (face.NumElements() == 0) strcat(s, "face.NumElements() = 0!");  // not an error in the future
00773     
00774     { // verify my node links
00775         for (int i=0; i<2; i++) {
00776             Node* n = getNodeLink(i);
00777             if (!n) {
00778                 sprintf(tmps, "nodelink[%d] is NULL!", i); 
00779                 strcat(s,tmps);
00780             }
00781             else if (!n->hasEdgeLink(this)) {
00782                 sprintf(tmps, "nodelink[%d] (%d) does not have a link back to us!", i, n->getIndex() );
00783                 strcat(s, tmps);
00784             }
00785         }
00786         
00787         // look for duplicates
00788         if (node[0] == node[1]) 
00789             strcat(s,"nodelinks point to the same node!\n");
00790     }
00791     
00792     { // verify my face links
00793         for (int i=0; i<face.NumElements(); i++) {
00794             Face* f = getFaceLink(i);
00795             if (!f) {
00796                 sprintf(tmps, "facelink[%d] is NULL!", i);
00797                 strcat(s, tmps);
00798             }
00799             else {
00800                 if (!f->hasEdgeLink(this)) {
00801                     sprintf(tmps, "facelink[%d] (%d) does not have a link back to us!", i, f->getIndex() );
00802                     strcat(s, tmps);
00803                 }
00804                 
00805                 // look for duplicate facelinks
00806                 for (int j=0; j<i; j++) {
00807                     if (f == getFaceLink(j)) {
00808                         sprintf(tmps, "facelink[%d] is a duplicate of facelink[%d]!", i, j);
00809                         strcat(s, tmps);
00810                     }
00811                 }
00812             }
00813         }
00814     }
00815     
00816     // if there's a problem, tell it
00817     if (strlen(s) > 1) {
00818         cerr << "Edge[" << my_index << "] is INSANE: " << s << endl;
00819         return(0);
00820     }
00821     
00822     //everything okay
00823     return(1);
00824 }
00825 
00826 ostream& operator<<(ostream& os, const Edge& e_in)
00827 {
00828      Edge& e = (Edge&)e_in;
00829 
00830          if (e.edgearray_p)
00831         os << "Edge#" << ((Edge&)e).getIndex() << ": ";
00832     else os << "Edge#UNLINKED: ";
00833     
00834     // print out the edge links
00835     os << ", nodelinks:" 
00836         << e.node[0]->getIndex() << " "
00837         << e.node[1]->getIndex();
00838     
00839    os << ", facelinks:";
00840    int i;
00841   for ( i=0; i<e.face.NumElements(); i++) 
00842           os << e.face[i]->getIndex() << " ";
00843                 
00844         // print out the tetra links
00845   os << ", tetralinks:";
00846   for ( i=0; i<e.tetra.NumElements(); i++) 
00847           os << e.tetra[i]->getIndex() << " ";
00848     
00849     return(os);
00850 }
00851 Face* Edge::getOtherFace(Face* f)
00852 {
00853         if (face.NumElements() > 2) {
00854                 cout << "can't use this function with this mesh" << endl;
00855                 return  NULL;
00856         }
00857         
00858         if (face.NumElements() == 1) {
00859                 if (face[0] == f) return (NULL);
00860         }
00861         
00862         if (face[0] == f) 
00863                 return(face[1]);
00864 
00865   else if (face[1] == f)
00866                 return(face[0]);
00867 
00868   else return(NULL);
00869 }
00870 int Edge::stepOffVerts(Point3D intPt) 
00871 {
00872         for (int i=0; i<2; i++) {
00873                 if (node[i]->p.Dist(intPt) < 0.00001) { 
00874                         //cout << "intersection on a vert" << endl;
00875                         intPt = .01*(node[(i+1)%3]->p - node[(i+0)%3]->p);                              
00876                         return i;
00877                 }
00878         }
00879         return -1;
00880 }
00881 int Edge::intersectsPlaneSweptByCuttingEdge(Edge* e_in, Point3D* intersection_p)
00882 { return 0;}
00883 
00884 int Edge::intersectsPlaneSweptFromEntryPt(Point3D entPt, Edge* cuttingEdge,Point3D *intPt)
00885 {                               
00886 
00887         Point3D p2(cuttingEdge->getNodeLink(0)->p.x,
00888                                                  cuttingEdge->getNodeLink(0)->p.y,
00889                                                  cuttingEdge->getNodeLink(0)->p.z);
00890         Point3D p3(cuttingEdge->getNodeLink(1)->p.x,
00891                                                  cuttingEdge->getNodeLink(1)->p.y,
00892                                                  cuttingEdge->getNodeLink(1)->p.z);
00893                                 
00894         int intersects = 0;
00895         intersects =crossesPlane(entPt, p2, p3, intPt);
00896 //      cout << "crosses plane: " << intersects << endl;
00897         if (intersects) {
00898                 intersects = intPt->insideTriangle(entPt, p2, p3);
00899         //      cout << "inside tri: " << intersects << endl;
00900         }
00901         return intersects;
00902 }
00903 
00904 // bump us back, based on them
00905 void Edge::ResolveMyself(Edge* other_edge)
00906 {
00907     // get locals
00908     double myradius = getRadius();
00909     double otherradius = other_edge->getRadius();
00910     double totalradius = otherradius + myradius;
00911 
00912     // loop for each of my nodes
00913     for (int i=0; i<2; i++) {
00914         Node* mynode = getNodeLink(i);
00915         // loop for each of their nodes
00916         for (int j=0; j<2; j++) {
00917             Node* othernode = other_edge->getNodeLink(j);
00918 
00919             // test distance
00920             double d = mynode->p.Dist(othernode->p);
00921 
00922             // if my half impinges on theirs, bump me back
00923             if (d < totalradius) 
00924                 mynode->p += (mynode->p - othernode->p) * (totalradius-d);
00925         }
00926     }
00927 }
00928 

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