/* hlr.cc */
/* This is the Hidden Line Removal (HLR) routine of the vmaster program. */
/* Its purpose is to take a linked list of lines and tris and edit the */
/* lines so that they are not obscured by the tris. */
/* #cxe- Fri Apr 19 12:22:29 PDT 2002 */

#include "vmaster.h"
bool TESTOUT=0;

Llist* hlr(Plist *allP, Llist *allL, Tlist *allT, camera the_camera)
{
bool Cmark=0; /* This is a diagnostic to set to see all cross marks. */
bool printit=1; /* This is to control what gets printed*/
/* Optimization 1: Looks for and deletes tri faces that are viewed on */
/* edge which can't block anything. */
Tlist *indexT=allT, *previousT=NULL;
while (indexT) {
 if (indexT->trionedge()) { 
/* Delete this tri now because it is not significant */
   if (previousT) /* if not top of the stack (something points here) */
    {previousT->setlink( indexT->querylink() );
     delete indexT;
     indexT = previousT->querylink();   }
   else /* deleting the first node - top of stack */
    {indexT= indexT->querylink();
     delete allT;
     allT=indexT;   }
   } /* end delete tri node */
else {  /* not on edge - merely skip to the next one */
previousT = indexT;
indexT = indexT->querylink(); }
} /* end while loop through each tri node */

/* Optimization 2: Cull tris and lines outside of view pyramid */
/* Acutally, this should probably be first */
/* I'll skip this for now....  */

/* Optimization 3: Cull shallow lines - but it now runs from main*/

/* Optimization 4: Look for tris that are completely obscured by */
/* other tris. This isn't easy, but potentially a good optimization. */
/* Best done with a sorted list of tris - front to back. */
/* I'll skip this for now....  */

/* Start main loops */
Llist *indexL=allL, *previousL=NULL;

/* Quick dump of lines - what's up?  */
/* while (indexL) {
cout << "#TEST:" << indexL << endl;
indexL= indexL->querylink();
} indexL=allL; */

while (indexL) {  /* process every line */
  if (TESTOUT) cout << "#-----checking line "
   << indexL->querypnumA() << "-"
   << indexL->querypnumB() << "--------------------" << endl;

       indexT=allT;  previousT=NULL;
  while (indexT) {   /* for each line, look at every tri */


/* Optimization 5: Use bounding box to see if the tri is anywhere near */
/* the line in our 2d view.  */
 if ( indexT->BBinterfere(indexL) ) { // cout << "X ";

line_tri_int_values t_l;              

switch ( indexT->line_interact(indexL, t_l) ) {
case -1:  { /* TOTALLY IGNORE */
/* [-1] Line is completely unrelated to tri - simply missed by BB check */

if (TESTOUT)
   cout << "\n#  against tri "
   << indexT->querypnumA() << "-"
   << indexT->querypnumB() << "-"
   << indexT->querypnumC() << " BB hit but unrelated." << endl;

break;} /* end of case -1 */

case 0:  {
/* [0] Line is completely within tri */

if (TESTOUT)
  cout << "\n#  against tri "
   << indexT->querypnumA() << "-"
   << indexT->querypnumB() << "-"
   << indexT->querypnumC() << " BB hit and completely enclosed." << endl;

t_l.Azt = Z_on_tri_from_xy(indexT,t_l.Ax,t_l.Ay);
t_l.Bzt = Z_on_tri_from_xy(indexT,t_l.Bx,t_l.By);

/* was this: */
/* if ( (t_l.Azl >= t_l.Azt) && (t_l.Bzl >= t_l.Bzt) ) */
/*now*/
if ( rgte(t_l.Azl, t_l.Azt) && rgte(t_l.Bzl, t_l.Bzt) )
{/* if line is above tri */
if (TESTOUT)
 cout << "#...tri has no effect on higher enclosed line" << endl;
        /*  IGNORE AND SKIP OUT  */
 break;
} /* end if line is above tri */
else
{ /* at least some of the line is below the tri */
  if ( rlte(t_l.Azl, t_l.Azt) && rlte(t_l.Bzl, t_l.Bzt) )
  { /* if tri is above line (obscures it) */
   if (TESTOUT)
   cout << "#...tri totally obscures lower enclosed line" << endl;
 
/* Draw it in a different color before deleting if hidscolor is on */
if ( strcmp(the_camera.hidscolor(),"off") ){
   cout << "p c " << the_camera.hidscolor() << endl;
   cout << "line "<<t_l.Ax<<","<<t_l.Ay
        <<" "<<t_l.Bx<<","<<t_l.By<< endl;
   cout << "p c white" << endl;}

        /* COMPLETELY REMOVE LINE FROM Llist */
   printit=0; /* this one doesn't get printed - it's hidden */
   if (previousL) /* if not top of the stack (something points here) */
    {previousL->setlink( indexL->querylink() );
     delete indexL;  /* Previous gets set to index anyway soon */
     indexL = previousL; } /* Previous is still the same! */
   else /* deleting the first node - top of stack */
    { if (indexL) indexL= indexL->querylink();
     delete allL;
     allL=indexL;   } /* end delete line node */

   indexT=NULL; /* no point in checking more tris - end loop */
   break;
  } /* end if tri is above line (obscures it) */
  else
    { /* tri pierced -  one endpiont above, one below */
    if (TESTOUT)
     cout << "#...tri is pierced by enclosed line" << endl;

  /* Find pierce point for totally enclosed line */
  if (!piercepoint(indexT, indexL->querypointA(), indexL->querypointB(), t_l))
   {cerr << "error: no pierce point of line through parallel tri [0]." << endl;}

if (the_camera.ppmark())
cout << "mark (" << t_l.Px << "," << t_l.Py << ") 4 "
     << the_camera.ppmark() << endl;

/* Add the pierce point to the point stack */
/* No checking for redundancy, but it could be done... */
/* if (not redundant) */
   { Plist *PPnode = new Plist;
     Vector P(t_l.Px, t_l.Py, t_l.Pz);
     PPnode->setup(0, P, allP);
     allP=PPnode; }
/* MAKE ADJUSTMENTS TO LINE */
  if ( (t_l.Azl - t_l.Azt) < (t_l.Bzl - t_l.Bzt) ) /* A is low */
   { indexL->setupA(allP); 
   /* Draw it in a different color before deleting if hidscolor is on */
   if ( strcmp(the_camera.hidscolor(),"off") ){
   cout << "p c " << the_camera.hidscolor() << endl;
   cout << "line "<<t_l.Ax<<","<<t_l.Ay
        <<" "<<t_l.Px<<","<<t_l.Py<< endl;
   cout << "p c white" << endl;}
   }
  else /* B is low */
   { indexL->setupB(allP); 
   /* Draw it in a different color before deleting if hidscolor is on */
   if ( strcmp(the_camera.hidscolor(),"off") ){
   cout << "p c " << the_camera.hidscolor() << endl;
   cout << "line "<<t_l.Bx<<","<<t_l.By
        <<" "<<t_l.Px<<","<<t_l.Py<< endl;
   cout << "p c white" << endl;}
   }

     break;
    } /* end else - tri pierced -  one endpiont above, one below */
} /* end else - at least some of the line is below the tri */

/* shouldn't get here! */
break;} /* end of case 0 */

case 1:  {
/* [1] Line has one endpoint in tri, one outside */
if (TESTOUT)
  cout << "\n#  against tri "
   << indexT->querypnumA() << "-"
   << indexT->querypnumB() << "-"
  << indexT->querypnumC() << " BB hit, 1 crossing, 1 point enclosed:" << endl;

if (Cmark)
cout << "mark (" << t_l.C1x << "," << t_l.C1y << ") 5 .1" << endl;

/* Check is B enclosed? */
if (
( is_within_or_on_angle(indexL->querypointB(),
                     indexT->querypointA(),
                     indexT->querypointB(),
                     indexT->querypointC())  ) &&
( is_within_or_on_angle(indexL->querypointB(),
                     indexT->querypointB(),
                     indexT->querypointC(),
                     indexT->querypointA())  )  )
{ /* If B is enclosed, switch with A for consistency later */
if (TESTOUT) cout<<"# A and B are being switched for convenience" << endl;
Plist *temp = indexL->queryA();
indexL->setupA( indexL->queryB() );
indexL->setupB( temp );  
/* This must get switched too! B's can die - don't matter here... */
float ftemp;
ftemp=t_l.Ax; t_l.Ax=t_l.Bx; t_l.Bx=ftemp;
ftemp=t_l.Ay; t_l.Ay=t_l.By; t_l.By=ftemp;
ftemp=t_l.Azl; t_l.Azl=t_l.Bzl; t_l.Bzl=ftemp;
 }

/* OK, now A is definitely the one enclosed */
t_l.Azt = Z_on_tri_from_xy(indexT, t_l.Ax, t_l.Ay);
/* t_l.Bzt = Z_on_tri_from_xy(indexT,t_l.Bx,t_l.By); is this needed? */
t_l.C1zt = Z_on_tri_from_xy(indexT, t_l.C1x, t_l.C1y);

/* cout <<"#TEST:Azl:" << t_l.Azl << " Azt:" << t_l.Azt
     << " C1zl:" << t_l.C1zl << " C1zt:" << t_l.C1zt << endl; */

/* Enclosed point and cross point are above tri - no effect */
if ( rgte(t_l.Azl, t_l.Azt) && rgte(t_l.C1zl, t_l.C1zt) ) {
     if (TESTOUT)
     cout<<"# enclosed and cross are above tri - ignoring" << endl;
 break;}

/* Enclosed point and cross point are below tri - simple cutoff */
if ( rlte(t_l.Azl, t_l.Azt) && rlte(t_l.C1zl, t_l.C1zt) ) {
     if (TESTOUT)
     cout<<"# enclosed and cross are below tri - simple cutoff" << endl;
   
/* Add new point to point list for the crossing point */
/* Really this should check to see if anything uses the enclosed point. */
/* If not, it should get recycled. This will add points to the point list */
/* kind of willy nilly.  */
   { Plist *CPnode = new Plist;
     Vector P(t_l.C1x, t_l.C1y, t_l.C1zl);
     CPnode->setup(0, P, allP);
     allP=CPnode; }

/* Draw it in a different color before deleting if hidscolor is on */
   if ( strcmp(the_camera.hidscolor(),"off") ){
   cout << "p c " << the_camera.hidscolor() << endl;
   cout << "line "<<t_l.Ax<<","<<t_l.Ay
        <<" "<<t_l.C1x<<","<<t_l.C1y<< endl;
   cout << "p c white" << endl;}

/* Set current Line's A point (enclosed) to the new point (crossing point) */
if (TESTOUT) cout << "# Changing A to last defined point here" << endl;
    indexL->setupA(allP);
break;} /* end line below tri, simple cutoff */

/* CLASH implied at this point - Find pierce point for 1 crosspoint */
if (!piercepoint(indexT, indexL->querypointA(), indexL->querypointB(), t_l))
{cerr << "error: no pierce point of line through parallel tri [1]." << endl;}

if (TESTOUT)
cout << "#Line pierces tri from top - one point enclosed..." << endl;

if (the_camera.ppmark())
cout << "mark (" << t_l.Px << "," << t_l.Py << ") 4 "
     << the_camera.ppmark() << endl;

/* Line dives into tri from top */
if (t_l.C1zl >= t_l.C1zt) {
   { Plist *PPnode = new Plist;
     Vector P(t_l.Px, t_l.Py, t_l.Pz);
     PPnode->setup(0, P, allP);
     allP=PPnode; }

/* Draw it in a different color before deleting if hidscolor is on */
   if ( strcmp(the_camera.hidscolor(),"off") ){
   cout << "p c " << the_camera.hidscolor() << endl;
   cout << "line "<<t_l.Ax<<","<<t_l.Ay
        <<" "<<t_l.Px<<","<<t_l.Py<< endl;
   cout << "p c white" << endl;}

/* Set current Lines A point (enclosed) to the new point (pierce point) */
    indexL->setupA(allP);
break;}

if (TESTOUT)
cout << "#Line pierces tri from bottom - one point enclosed..." << endl;
/* If still here, then it must be a pierce from the bottom */
/* Add pierce point to list */
Plist *PPnode = new Plist;
Vector P(t_l.Px, t_l.Py, t_l.Pz);
PPnode->setup(0, P, allP);
allP=PPnode; 

/* Add Cross point to list */
Plist *CPnode = new Plist;
P.gg_set2(t_l.C1x, t_l.C1y, t_l.C1zl);
CPnode->setup(0, P, allP);
allP=CPnode; 

/* Add a new line segment from enclosed point A to pierce point */
Llist *extrapart = new Llist;
extrapart->setup( indexL->queryA(), PPnode, indexL->querylink() );

/* Fix up the old line to go from the cross point to B which is OK as is */
indexL->setupA(CPnode);

/* INSERT new node after in list so it is considered next */
indexL->setlink(extrapart); 

/* Draw it in a different color before deleting if hidscolor is on */
   if ( strcmp(the_camera.hidscolor(),"off") ){
   cout << "p c " << the_camera.hidscolor() << endl;
   cout << "line "<<t_l.Px<<","<<t_l.Py
        <<" "<<t_l.C1x<<","<<t_l.C1y<< endl;
   cout << "p c white" << endl;}

break;} /* end of case 1 */

case 2:  {
/* [2] Line has both endpoints outside of tri, crosses tri twice */
if (TESTOUT) cout << "\n#  against tri "
   << indexT->querypnumA() << "-"
   << indexT->querypnumB() << "-"
   << indexT->querypnumC() << " BB hit, 2 crossing, 0 enclosed:" << endl;
if (Cmark){
cout << "mark (" << t_l.C1x << "," << t_l.C1y << ") 5 .1" << endl;
cout << "mark (" << t_l.C2x << "," << t_l.C2y << ") 3 .1" << endl;}

/* OK, get Zs for everyone */
/* t_l.Azt = Z_on_tri_from_xy(indexT, t_l.Ax, t_l.Ay); is this needed? */
/* t_l.Bzt = Z_on_tri_from_xy(indexT,t_l.Bx,t_l.By);  is this needed? */
t_l.C1zt = Z_on_tri_from_xy(indexT, t_l.C1x, t_l.C1y);
t_l.C2zt = Z_on_tri_from_xy(indexT, t_l.C2x, t_l.C2y);

/* Both cross points on line are above cross points on tri - no effect */
if ( (t_l.C1zl >= t_l.C1zt) && (t_l.C2zl >= t_l.C2zt) ) {
   if (TESTOUT) cout << "#No effect here!\n";
   break;}

/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
/* I'm assuming that A is closest to C1 - if this is  */
/*  not true switch them here!!! */
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
{ Vector P1(t_l.C1x, t_l.C1y, t_l.C1zl),
         P2(t_l.C2x, t_l.C2y, t_l.C2zl),
         A=indexL->querypointA();
if ( A.gg_distance(P1) > A.gg_distance(P2) )
{ Plist *temp = indexL->queryA();
  indexL->setupA( indexL->queryB() );
  indexL->setupB( temp );   } 
} /* end of block that switches A and B if not right */

/* Both cross points are below cross points on tri - simple cutout */
if ( (t_l.C1zl <= t_l.C1zt) && (t_l.C2zl <= t_l.C2zt) ) {

/* Add 2 new points to point list for the crossing points */
/* Doesn't prevent redundant points. Oh well... */
/* Here's the first point - C1 to go to the original line's A */
   { Plist *P1node = new Plist;
     Vector P(t_l.C1x, t_l.C1y, t_l.C1zl);
     P1node->setup(0, P, allP);
     allP=P1node; }
/* Set current Lines A point (enclosed) to the new point (crossing point) */
if (TESTOUT)
cout << "# Changing B to last defined point (C1) here" << endl;
Plist *dontloseB = indexL->queryB();
    indexL->setupB(allP);

/* Here's the second point - C2 to go to the original line's B */
   { Plist *P2node = new Plist;
     Vector P(t_l.C2x, t_l.C2y, t_l.C2zl);
     P2node->setup(0, P, allP);
     allP=P2node; }

/* Now add the line with this latest point (C2) and dontloseB */
Llist *extrapart = new Llist;
extrapart->setup( dontloseB, allP, indexL->querylink() );

/* INSERT new node after in list so it is considered next */
indexL->setlink(extrapart); 

/* Draw it in a different color before deleting if hidscolor is on */
   if ( strcmp(the_camera.hidscolor(),"off") ){
   cout << "p c " << the_camera.hidscolor() << endl;
   cout << "line "<<t_l.C1x<<","<<t_l.C1y
        <<" "<<t_l.C2x<<","<<t_l.C2y<< endl;
   cout << "p c white" << endl;}

break;} /* end if - 2 cross with line completely behind tri */

/* CLASH implied at this point - Find pierce point for 2 crosspoint */
if (!piercepoint(indexT, indexL->querypointA(), indexL->querypointB(), t_l))
{cerr << "error: no pierce point of line through parallel tri [2]." << endl;}

if (TESTOUT)
cout << "#Line pierces tri - crosses tri twice..." << endl;

if (the_camera.ppmark())
cout << "mark (" << t_l.Px << "," << t_l.Py << ") 4 "
     << the_camera.ppmark() << endl;

/* Add 2 new points to point list for the crossing points */
/* Doesn't prevent redundant points. Oh well... */
/* Here's the pierce point - to go to the higher of A or B */
Plist *PPnode = new Plist;
Vector P(t_l.Px, t_l.Py, t_l.Pz);
PPnode->setup(0, P, allP);
allP=PPnode; 

if ( (t_l.C1zl-t_l.C1zt) > (t_l.C2zl-t_l.C2zt) ) 
{ /* then pierce point goes to A */
/* Here's the second point - C2 to go to the original line's B */
{ Plist *P2node = new Plist;
  Vector P(t_l.C2x, t_l.C2y, t_l.C2zl);
  P2node->setup(0, P, allP);
  allP=P2node; }

if (TESTOUT)
cout << "# Changing B to pierce point here" << endl;

Plist *dontloseB = indexL->queryB();
    indexL->setupB(PPnode); /* Set B to Pierce Point */

/* Now add the line with this latest point (C2) and dontloseB */
Llist *extrapart = new Llist;
extrapart->setup( dontloseB, allP, indexL->querylink() );

/* INSERT new node after in list so it is considered next */
indexL->setlink(extrapart); 

/* Draw it in a different color before deleting if hidscolor is on */
   if ( strcmp(the_camera.hidscolor(),"off") ){
   cout << "p c " << the_camera.hidscolor() << endl;
   cout << "line "<<t_l.C2x<<","<<t_l.C2y
        <<" "<<t_l.Px<<","<<t_l.Py<< endl;
   cout << "p c white" << endl;}

break; } /* end if - case where pierce point goes to A */

else { /* then pierce point goes to B */
/* Here's the second point - C1 to go to the original line's B */
{ Plist *P2node = new Plist;
  Vector P(t_l.C1x, t_l.C1y, t_l.C1zl);
  P2node->setup(0, P, allP);
  allP=P2node; }

if (TESTOUT)
cout << "# Changing A to pierce point here" << endl;

Plist *dontloseA = indexL->queryA();
    indexL->setupA(PPnode); /* Set A to Pierce Point */

/* Now add the line with this latest point (C2) and dontloseB */
Llist *extrapart = new Llist;
extrapart->setup( dontloseA, allP, indexL->querylink() );

/* INSERT new node after in list so it is considered next */
indexL->setlink(extrapart); 

/* Draw it in a different color before deleting if hidscolor is on */
   if ( strcmp(the_camera.hidscolor(),"off") ){
   cout << "p c " << the_camera.hidscolor() << endl;
   cout << "line "<<t_l.C1x<<","<<t_l.C1y
        <<" "<<t_l.Px<<","<<t_l.Py<< endl;
   cout << "p c white" << endl;}

break;}/* end else - pierce point goes to B */

/*We shouldn't be here, should we?*/
break;} /* end of case 2 */

} /* end of switch for various interaction cases */

} /* end of case where tri is likely to affect line based on BB */

  else /*Normally, we'd just ignore this case */
if (indexT && TESTOUT) cout << "\n#  against tri "
   << indexT->querypnumA() << "-"
   << indexT->querypnumB() << "-"
   << indexT->querypnumC() << " no BB relation." << endl;


     previousT = indexT;
     if (indexT) indexT = indexT->querylink(); 
  } /* end while loop through each tri node */

/* Print line here on the fly as the line is figured out... */
if (printit) cout << "line " << indexL << endl; 
else printit = 1;

previousL = indexL;
if (indexL) indexL = indexL->querylink(); 
} /* end while loop through each line node */

return allL; } /* end of the hidden line removal function */


/* Other functions used in HLR */

/* check what kind of interaction the supplied line has with the tri */
/* Return values: -1=unrelated, 0=enclosed, 1=one point in, 2=spans */
int Tlist::line_interact(Llist *L, line_tri_int_values &t_l)
{ 
/* line/triface critical intersection values are:
  Ax, Ay, Azl, Azt, Bx, By, Bzl, Bzt, Px, Py, Pz,
  C1x, C1y, C1zl, C1zt, C2x, C2y, C2zl, C2zt     */
float crossX, crossY, crossZl, crossZt;
Vector VLA = L->querypointA(),
       VLB = L->querypointB(),
       VTA = querypointA(),
       VTB = querypointB(),
       VTC = querypointC();
/* This is stuff we know isn't going to change here so set it now:*/
t_l.Ax = VLA.gg_valX(); t_l.Ay = VLA.gg_valY(); t_l.Azl = VLA.gg_valZ();
t_l.Bx = VLB.gg_valX(); t_l.By = VLB.gg_valY(); t_l.Bzl = VLB.gg_valZ();

/*1*/
if ( intersection_2d(VLA, VLB, VTA, VTC, crossX, crossY, crossZl, crossZt) )
{
if (TESTOUT) cout << "\n#....Line crosses 1-3" << endl;
/* SET t_l #1 */
t_l.C1x = crossX; t_l.C1y = crossY; t_l.C1zl = crossZl; t_l.C1zt = crossZt;

/*2*/
  if ( intersection_2d(VLA, VLB, VTB, VTC, crossX, crossY, crossZl, crossZt) )
   {
    if (TESTOUT) cout << "\n#....Line crosses 1-3 and also 2-3" << endl;
    /* SET t_l's C #2 */
  t_l.C2x = crossX; t_l.C2y = crossY; t_l.C2zl = crossZl; t_l.C2zt = crossZt;
     return 2; } /* end of if level 2 */
  else
   {
      if (TESTOUT) cout << "\n#....Line crosses 1-3 but not 2-3" << endl;
/*3*/
     if ( intersection_2d(VLA, VLB, VTA, VTB, crossX, crossY, crossZl, crossZt) )
      {
      if (TESTOUT) cout << "\n#....Line crosses 1-3 but not 2-3 yet also 1-2" << endl;
      /* SET t_l's C #2 */ 
  t_l.C2x = crossX; t_l.C2y = crossY; t_l.C2zl = crossZl; t_l.C2zt = crossZt;
        return 2; } /* end of if level 3 */
     else{
      if (TESTOUT) cout << "\n#....Line crosses 1-3 but not 2-3 nor 1-2" << endl;
      /* Check it see if the point crosses at a vertex of the tri */
            if ( crosses_at_vertex(VLA, VLB, VTA, VTB, VTC, crossX, crossY ) )
            { 
          if (TESTOUT) cout 
          << "\n#....Line cross 1-3,yes; 2-3,no; 1-2,no; vertex, yes" << endl;
             /* SET t_l's C #2 */
             t_l.C2x = crossX; t_l.C2y = crossY;
             t_l.C2zl = crossZl; t_l.C2zt = crossZt;
             return 2; }
             else {
          if (TESTOUT) cout 
          << "\n#....Line cross 1-3,yes; 2-3,no; 1-2,no; vertex, no" << endl;
             return 1; } /* else no cross at vertex really its a 1 */
        } /* end of else not 1-2 so check vertex leak */
  } /* end of else level 2*/
}/* end of if level 1 */
else
{
    if (TESTOUT) cout << "\n#....Line doesn't cross 1-3" << endl;
/*2*/
  if ( intersection_2d(VLA, VLB, VTB, VTC, crossX, crossY, crossZl, crossZt) )
   { 
    if (TESTOUT) cout << "\n#....Line doesn't cross 1-3 yet crosses 2-3" << endl;

    /* SET t_l #1 */ 
   t_l.C1x = crossX; t_l.C1y = crossY; t_l.C1zl = crossZl; t_l.C1zt = crossZt;

/*3*/
     if ( intersection_2d(VLA, VLB, VTA, VTB, crossX, crossY, crossZl, crossZt) )
        {

         if (TESTOUT) cout << "\n#....Line doesn't cross 1-3 yet crosses 2-3 and 1-2" << endl;
         /* SET t_l's C #2 */
    t_l.C2x = crossX; t_l.C2y = crossY; t_l.C2zl = crossZl; t_l.C2zt = crossZt;
          return 2; } /* end of if level 3 */
     else {
          if (TESTOUT) cout 
          << "\n#....Line doesn't cross 1-3 yet crosses 2-3 but not 1-2" << endl;
/* Check it see if the point crosses at a vertex of the tri */
            if ( crosses_at_vertex(VLA, VLB, VTA, VTB, VTC, crossX, crossY ) )
            { 
/*
cerr << "TEST:2 LA:" << VLA <<  " LB:" << VLB << endl
     <<  "TA:" << VTA <<  " TB:" << VTB << " TC:" << VTC << endl
     <<  "cross:(" << crossX << "," << crossY << ","
     << crossZl << " or " << crossZt << ")" << endl;
*/

          if (TESTOUT) cout 
          << "\n#....Line cross 1-3,no; 2-3,yes; 1-2,no; vertex, yes" << endl;
             /* SET t_l's C #2 */
             t_l.C2x = crossX; t_l.C2y = crossY;
             t_l.C2zl = crossZl; t_l.C2zt = crossZt;
             return 2;
            }

            else {
          if (TESTOUT) cout 
          << "\n#....Line cross 1-3,no; 2-3,yes; 1-2,no; vertex, no" << endl;
           return 1;}
             }

   }/* end of if level 2 */
  else
  {
    if (TESTOUT) cout << "\n#....Line doesn't cross 1-3 nor 2-3" << endl;
/*3*/
     if ( intersection_2d(VLA, VLB, VTA, VTB, crossX, crossY, crossZl, crossZt) )
   {


    if (TESTOUT) cout << "\n#....Line doesn't cross 1-3 nor 2-3 yet does cross 1-2" << endl;
    /* SET t_l #1 */ 
   t_l.C1x = crossX; t_l.C1y = crossY; t_l.C1zl = crossZl; t_l.C1zt = crossZt;

      /* Check it see if the point crosses at a vertex of the tri */
            if ( crosses_at_vertex(VLA, VLB, VTA, VTB, VTC, crossX, crossY ) )
            { 
          if (TESTOUT) cout 
          << "\n#....Line cross 1-3,no; 2-3,no; 1-2,yes; vertex, yes" << endl;
             /* SET t_l's C #2 */
             t_l.C2x = crossX; t_l.C2y = crossY;
             t_l.C2zl = crossZl; t_l.C2zt = crossZt;
             return 2; }
             else {
          if (TESTOUT) cout 
          << "\n#....Line cross 1-3,no; 2-3,no; 1-2,yes; vertex, no" << endl;
       return 1; }
     } /* end if line crosses only 1-2 check vertex leak */
     else
     {
    if (TESTOUT) cout << "\n#....Line cross 1-3,no; 2-3,no; 1-2,no" << endl;
/*4*/
       if ( is_within_or_on_angle(VLA, VTA, VTB, VTC) )
       {
        if (TESTOUT) cout <<
        "\n#....Line cross 1-3,no; 2-3,no; 1-2,no; A in 1,yes" << endl;

/*5*/
          if ( is_within_or_on_angle(VLA, VTB, VTA, VTC) )
            {
        if (TESTOUT) cout << "\n#....Line cross 1-3,no; 2-3,no; 1-2,no; "
                << "A in 1,yes; A in 2,yes" << endl;
             /*Needs another test to verify that it's really
                completely inside the tri. It could be that the line
                comes from somewhere unrelated to an endpoint
                at a tri vertex. Simple - check the other point to
                see if its in the tri too. If not, -1 unrelated */
            if ( !is_within_or_on_angle(VLB, VTA, VTB, VTC) ||
                 !is_within_or_on_angle(VLB, VTB, VTA, VTC) ){
        if (TESTOUT) cout << "\n#....Line cross 1-3,no; 2-3,no; 1-2,no; "
                << "A in 1,yes; A in 2,yes; B in 1||2,no" << endl;
                return -1;
               }/*end if no,no,no,yes,yes,no to B in tri -1 */

/*Before we take a nap, it looks like this is a good place to point out
that there is another case unaccounted for. If a line is in a tri and
escapes through a vertex. It makes it to here and gets listed as a 0.
I've fixed all the 1s that needed to be upgraded to 2s by this, but
this is where 0s should be checked to see if they're really 1s. */


               return 0; } /* end if no,no,no,yes,yes */
          else
            {
        if (TESTOUT) cout << "\n#....Line cross 1-3,no; 2-3,no; 1-2,no; "
                << "A in 1,yes; A in 2,no" << endl;
              return -1;}
       }
       else
           {
        if (TESTOUT) cout << "\n#....Line cross 1-3,no; 2-3,no; 1-2,no; "
                << " A in 1, no" << endl;
             return -1;}
    } /* end of else #4 */
  } /* end of else #3 */
} /* end of else #1 */
   
/*  cout << "\nSpotcheck!\n";
  cout << "Cx:" << crossX << " Cy:" << crossY;
  cout << " CzL: " << crossZl << " CzT:" << crossZt << endl;
  cout << "LA:" << VLA << " LB:" << VLB << endl;
  cout << "TA:" << VTA << " TB:" << VTB << endl; */

/* Something's wrong if we get here! */
return -2;}

/* Function that will look at two lines and consider only the XY */
/* components when looking for an intersection. The intersection must be */
/* inbetween the endpoints of both lines to be valid. The C values are to */
/* be able to return helpful info about where the int is. */
/* The line and tri notation just represent two lines */
bool intersection_2d(Vector &LA, Vector &LB, Vector &TA, Vector &TB,
                     float &Cx, float &Cy, float &Czl, float &Czt){

float deltaLx = LB.gg_valX() - LA.gg_valX();
float deltaTx = TB.gg_valX() - TA.gg_valX();

/* Check if both are vertical */
if (!deltaLx && !deltaTx) { /*cout << "#....both vertical";*/ return 0;}

float slopeL; float slopeT;

/* Check these deltas - if either 0 avoid div/0 error!!! */
if (!deltaLx) /* Line line is vertical */
{ /* Define this locally for now since it may be div/0 if we're not here */
  slopeT = (TB.gg_valY() - TA.gg_valY() ) / deltaTx;
  Cx = LA.gg_valX(); /* x = any vertical X value */
  /*     Y = m * X + b        */
float intercept =  TA.gg_valY() - TA.gg_valX() * slopeT;
Cy = slopeT * Cx  + intercept;

/* Do this first because it can be useful even if it doesn't look like */
/* they cross from here. We can check later to see if the line crosses at */
/* a tri vertex. */
/* Calculate Cz's */
Czl = zvalbetween2pts(LA, LB, Cx, Cy);
Czt = zvalbetween2pts(TA, TB, Cx, Cy);

/* Check to see the lines cross where it matters */
if (
   ( (rlte(Cy,LA.gg_valY()) && rlte(Cy,LB.gg_valY())) ||
     (rgte(Cy,LA.gg_valY()) && rgte(Cy,LB.gg_valY())) ) ||
   ( (rlte(Cy,TA.gg_valY()) && rlte(Cy,TB.gg_valY())) ||
     (rgte(Cy,TA.gg_valY()) && rgte(Cy,TB.gg_valY())) )  
) {
/*  cout << "#....Lline is vertical, but int is off line"; */
return 0;}

/* cout << "#....Lline is vertical should be good"; */
return 1; }

/* Line slope is safe to define now */
slopeL = (LB.gg_valY() - LA.gg_valY() ) / deltaLx;

if (!deltaTx) /* Tri line is vertical */
{ Cx = TA.gg_valX(); /* x = any vertical X value */
  /*     Y = m * X + b        */
float intercept = LA.gg_valY() - LA.gg_valX() * slopeL;
Cy = slopeL * Cx  + intercept;

/* Calculate Cz's */
Czl = zvalbetween2pts(LA, LB, Cx, Cy);
Czt = zvalbetween2pts(TA, TB, Cx, Cy);

/* Check to see the lines cross where it matters */
if (
   ( (rlte(Cy,TA.gg_valY()) && rlte(Cy,TB.gg_valY())) ||
     (rgte(Cy,TA.gg_valY()) && rgte(Cy,TB.gg_valY())) )  ||
   ( (rlte(Cy,LA.gg_valY()) && rlte(Cy,LB.gg_valY())) ||
     (rgte(Cy,LA.gg_valY()) && rgte(Cy,LB.gg_valY())) )
){
/*  cout << "#....Tline is vertical, but int is off line"; */
 return 0;}

/* cout << "#....Tline is vertical should be good"; */
return 1; }

/* Tri slope is safe to define here */
slopeT = (TB.gg_valY() - TA.gg_valY() ) / deltaTx;
float Xdenom = slopeL - slopeT;

/* Check  - if Xdenom == 0 then parallel lines div/0 error #2 */
if (!Xdenom) {
/* cout << "#....the lines are parallel"; */
return 0;}

/* Ok, at this point, neither are vertical and they're not parallel */
float bT= TA.gg_valY() - slopeT * TA.gg_valX(),
      bL= LA.gg_valY() - slopeL * LA.gg_valX();
Cx = (bT - bL) / Xdenom;
Cy = slopeT * Cx + bT;

/* Calculate Cz's */
Czl = zvalbetween2pts(LA, LB, Cx, Cy);
Czt = zvalbetween2pts(TA, TB, Cx, Cy);

/* Check to see if Cx,Cy = LA || LB || TA || TB, if so, then not really int */
/* Check to see if intersection is actually on the two lines */
/* Check to see the lines cross where it matters */
/* But have Cz's ready to check later if the line really slips between */
/* two tris. That can't be checked here. */

/* First, for horizontal lines, special case (verts are done earlier) */
if ( ( !(TA.gg_valY()-TB.gg_valY())) || ( !(LA.gg_valY()-LB.gg_valY())))
 /* is horizontal */ {
if( (rlte(Cx,TA.gg_valX()) && rlte(Cx,TB.gg_valX())) ||
     (rgte(Cx,TA.gg_valX()) && rgte(Cx,TB.gg_valX())) ||
     (rlte(Cx,LA.gg_valX()) && rlte(Cx,LB.gg_valX())) ||
     (rgte(Cx,LA.gg_valX()) && rgte(Cx,LB.gg_valX()))   
   ) {
/* cout << "#....one line horizontal and int is off line"; */
 return 0;}
} /* end special checking treatment for horizontal */
else
{
/* General case */
if (
   ( (rlte(Cy,TA.gg_valY()) && rlte(Cy,TB.gg_valY())) ||
     (rgte(Cy,TA.gg_valY()) && rgte(Cy,TB.gg_valY())) ||
     (rlte(Cx,TA.gg_valX()) && rlte(Cx,TB.gg_valX())) ||
     (rgte(Cx,TA.gg_valX()) && rgte(Cx,TB.gg_valX())) ) ||
   ( (rlte(Cy,LA.gg_valY()) && rlte(Cy,LB.gg_valY())) ||
     (rgte(Cy,LA.gg_valY()) && rgte(Cy,LB.gg_valY())) ||
     (rlte(Cx,LA.gg_valX()) && rlte(Cx,LB.gg_valX())) ||
     (rgte(Cx,LA.gg_valX()) && rgte(Cx,LB.gg_valX())) )
 ) {
/* cout << "#....lines are ok, but int is off line"; */
 return 0;}
} /* end else (lines are not horizontal) lines were checked */


/* cout << "Status check:" << endl; 
   cout <<"TAx:" << TA.gg_valX() <<" TAy:"<< TA.gg_valY() << endl 
     <<"TBx:" << TB.gg_valX() <<" TBy:"<< TB.gg_valY() << endl
     <<"LAx:" << LA.gg_valX() <<" LAy:"<< LA.gg_valY() << endl
     <<"LBx:" << LB.gg_valX() <<" LBy:"<< LB.gg_valY() << endl
     <<"slopeT:" << slopeT <<" slopeL:"
      << slopeL <<" Xdenom:"<< Xdenom<< endl
     <<"Cx:" << Cx <<" Cy:" << Cy << endl;  */

/* cout << "#....normal lines intersect and all is ok"; */
return 1; /* must be a good intersection if it gets here unscathed */
 } /* end of intersection_2d function */


/* Function to interpolate the Z value of a line whose XY coords are */
/* known along a 3d line */
float zvalbetween2pts(Vector A, Vector B, float Tx, float Ty)
{
float Ax = A.gg_valX(),
      Ay = A.gg_valY(),
      Az = A.gg_valZ(),
      Bx = B.gg_valX(),
      By = B.gg_valY(),
      Bz = B.gg_valZ(),
Tz = Az - ( sqrt( pow(Ax-Tx,2) + pow(Ay-Ty,2) ) * (Az-Bz) /
    sqrt( pow(Ax-Bx,2) + pow(Ay-By,2) ) );
 
/* NICE TRY, BUT SERIOUSLY BOGUS! 
 float z;
 Vector T1(1,1,0), T2(x,y,0);
 T2 = (A*T1) - T2;
 T1 *= (A-B);
 z = ( T2.gg_magnitude() / T1.gg_magnitude() ) * ( A.gg_valZ()-B.gg_valZ() ) +
     A.gg_valZ();
*/ 

/* cout << "#Zvalbetween2pts: check:" << A << " " << B */
/*      << " Tx:" << Tx << " Ty:" << Ty << " Tz:" << Tz << endl; */

return Tz;}


/* Best explained like this - P is the baseball, B is homeplate, */
/* A is the left field foul pole, C is the right field foul pole. */
/* This function determines whether the ball is fair or foul. */
/* Note: Whoa, there is some fucked up shit here. The gg_angle functions */
/* were playing games with my vectors. If used with the basepoint arg, */
/* the vectors get messed up. I tried to fix this by not making them refs */
/* in vector.h, but it didn't cure it. I am baffled. */
/* Other Note: This function sucks. It uses 3d stuff heavily which is */
/* stupid since I'm only looking at X&Y. It is also very sensitive to */
/* rounding problems. I amost don't believe it works. */
/* I added a fudge factor. Still lame..... */
bool is_within_angle(Vector P, Vector B, Vector A, Vector C)
{ float Aangle, Cangle, ACangle;
  Vector XY(1,1,0);
  A*=XY; B*=XY; C*=XY; P*=XY; A-=B; C-=B; P-=B; 
  ACangle = A.gg_angle(C);
  Aangle = A.gg_angle(P);
  Cangle = C.gg_angle(P);
/* Case where P is on a line... Or damn close to it... */
if ( (fabs(Aangle) < MINANGVAL) || (fabs(Cangle) < MINANGVAL) ) return 0;
/* P isn't in the angle */
if ( (Aangle+Cangle - ACangle) > MINANGVAL ) return 0;
else
 return 1;}

/* Very similar to is_within_angle but I couldn't think of an elegant way */
/* to reuse it. So I didn't... */
bool is_within_or_on_angle(Vector P, Vector B, Vector A, Vector C)
{ float Aangle, Cangle, ACangle;
  Vector XY(1,1,0);
  A*=XY; B*=XY; C*=XY; P*=XY; A-=B; C-=B; P-=B; 
  ACangle = A.gg_angle(C);
  Aangle = A.gg_angle(P);
  Cangle = C.gg_angle(P);
/* cout <<"#is_within_or_on_angle:" << Aangle+Cangle <<" - "<<ACangle<<endl; */
/* cout <<"#is_within_or_on_angle:" <<" > "<< MINANGVAL <<endl; */
/* P isn't in the angle */
if ( (Aangle+Cangle - ACangle) > MINANGVAL ) return 0;
else
{
/*  cout <<"#is_within_or_on_angle:should arrive here ok..." <<endl; */
 return 1;}
}

/* Realistic Less Than or Equal too */
bool rlte(float A, float B)
{ if (A < B) return 1; /* obvious no more ops needed */
  if ( fabs(A-B) < MINVAL ) return 1; /* second chance - kind of = */
  return 0; /* Neither less nor close enough */     };

/* Realistic Greater Than or Equal too */
bool rgte(float A, float B)
{ if (A > B) return 1; /* obvious no more ops needed */
  if ( fabs(A-B) < MINVAL ) return 1; /* second chance - kind of = */
  return 0; /* Neither less nor close enough */     };

/* Realistic Equal too */
bool req(float A, float B)
{ if ( fabs(A-B) < MINVAL ) return 1; /* kind of = */
  return 0; /* Not close enough */     };

/* Function that looks at where a line parallel to the Z axis will pierce */
/* the plane of a given triangle. The location of the line is supplied */
/* with x,y coords and the result is z of the hit. */
float Z_on_tri_from_xy(Tlist *T, float x, float y)
{Vector A = T->querypointA(),
        B = T->querypointB() - A,
        C = T->querypointC() - A, /* -A to set to 0,0,0 */
        N = (B & C); /* Normal (cross) to tri from 0,0,0 */
x -= A.gg_valX(); /* Adujst the x and y's to to reflect origin */
y -= A.gg_valY();
if ( !N.gg_valZ() ) return 0; /*on edge? No Z in normal!*/
return ( ( ( -N.gg_valX()*x - N.gg_valY()*y ) / N.gg_valZ() ) 
                + A.gg_valZ() ) ;
}



unsigned int piercepoint(Tlist *T, Vector A, Vector B, line_tri_int_values &t_l )
{Vector TA = T->querypointA(),
        TB = T->querypointB() - TA,
        TC = T->querypointC() - TA, /* -A to set to 0,0,0 */
        N = (TB & TC); /* Normal (cross) to tri from 0,0,0 */
A -= TA; B -= TA; /* set up line's points to be in context */

float denomenator = N | (A-B) ; 
/* Hmmm, I don't really know what to do in this case.... */
if (denomenator < MINVAL)
/* if (denomenator < .005) */
{
 t_l.Px = t_l.C1x; t_l.Py = t_l.C1y; t_l.Pz = t_l.C1zt; return 0;}

/* cout << "TEST:denomenator:" << denomenator << endl; */

t_l.Px = 
  (( N.gg_valY()*(A.gg_valY() * B.gg_valX() - A.gg_valX() * B.gg_valY()) +
    N.gg_valZ()*(A.gg_valZ() * B.gg_valX() - A.gg_valX() * B.gg_valZ()) )
                         / denomenator) + TA.gg_valX();
t_l.Py = 
  (( N.gg_valX()*(A.gg_valX() * B.gg_valY() - A.gg_valY() * B.gg_valX()) +
    N.gg_valZ()*(A.gg_valZ() * B.gg_valY() - A.gg_valY() * B.gg_valZ()) ) 
                         / denomenator) + TA.gg_valY();
t_l.Pz = 
  (( N.gg_valX()*(A.gg_valX() * B.gg_valZ() - A.gg_valZ() * B.gg_valX()) +
    N.gg_valY()*(A.gg_valY() * B.gg_valZ() - A.gg_valZ() * B.gg_valY()) )
                         / denomenator) + TA.gg_valZ();
return 1; }


bool crosses_at_vertex(
       Vector A, Vector B, Vector a, Vector b, Vector c, float x, float y )
{ Vector nullZ(1,1,0), C(x,y,0);
A *= nullZ; B *= nullZ; a *= nullZ; b *= nullZ; c *= nullZ;

/* Endpoints can't be on vertices and be considered breaking out there */
/* or even on a vertex here and breaking out on a vertex somewhere else. */
if ( (A==a) || (A==b) || (A==c) ) return 0;
if ( (B==a) || (B==b) || (B==c) ) return 0;

/* Check to make sure that the cross point is on a vertex */
if ( !((C==a) || (C==b) || (C==c)) ) return 0;

/* If crosses at vertex a and either A or B is in the angle at a then ok */
/*NEW- Whoa, this was a nasty one... Turns out that my description was
quite right above but executed wrong below. "either A or B" but down
below, the function is a simple OR which can imply BOTH A or B. That's
wrong. This gave false hits where the line seemed like it was going
through a vertex, but it had already been chopped clear of the vertex
by another tri. This actually set up an infinite loop! So for the line
to escape at a vertex legitimately, it needs to have one and only one
end point inside the vertex's angle. If both are there, then it's not
crossing at a vertex. The correct function is an XOR. */
if ( (C==a) &&
( !xnor( is_within_angle(A, a, b, c), is_within_angle(B, a, b, c)) ) )
{return 1;}

/* If crosses at vertex b and either A or B is in the angle at b then ok */
if ( (C==b) &&
( !xnor( is_within_angle(A, b, a, c), is_within_angle(B, b, a, c)) ) )
{return 1;}

/* If crosses at vertex c and either A or B is in the angle at c then ok */
if ( (C==c) &&
( !xnor( is_within_angle(A, c, b, a), is_within_angle(B, c, b, a)) ) )
{return 1;}

/* The crossing point isn't at a vertex. It had it's chance... */
return 0; }

/* Simple XNOR Function... damn, it kept popping up! */
/* Of course, XOR is !XNOR */
bool xnor(bool m, bool n) { return ((m||!n)&&(!m||n)); }

