/* vmaster.cc */
/* This program takes 3d model data and constructs a 2d view for
 * subsequent plotting.                                  */
/* #cxe-Started Mon Mar 18 20:10:58 PST 2002 */
/* $Date: 2002/04/30 09:51:26 $ - $Revision: 1.5 $ */

#include "vmaster.h"

/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
/* Start of main=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
int main(int argc, char **argv)
{ camera the_camera; the_camera.ppmark(0);
  dealwithoptions(argc, argv, the_camera);

/* At this point we can use the following functions as values */
/* the_camera.campoint(), the_camera.tarpoint(), the_camera.aratio(), */
/* the_camera.zoom(), the_camera.roll(), the_camera.hlr() */

/* Must start out as null because that the end (first really) of the */
/* linked list signal. The second will point back to the first, but the */
/* first starts out with this. */
Plist *allpoints=NULL;
Redlist *redpoints=NULL;
Llist *lines=NULL;
Tlist *tris=NULL;

for (; optind < argc; ++optind)
{ cout << "# File is " << argv[optind] << endl; 
/*  cout << "argv[" << optind << "] is " << argv[optind] << ".\n";  */

cxe_finputline inputdata( argv[optind] ); 

while ( !inputdata.eof() ) {
inputdata.readnextline();

if ( inputdata.checkfor("#!") ) continue; /* ignore if comment */

inputdata.stripallbut("0123456789.-+eE"); /* clean it up to numbers */

/* -------------------------------------- */
/* Start analyzing and interpreting input */
/* -------------------------------------- */

/* Added this to keep it from producing errors when it's null */
if (inputdata.wordcount())
/* Check out form of the input based on number of fields */
switch ( inputdata.wordcount() ) {

/* Function to handle data in 2 part format (line by pnums) */
case 2:{
unsigned int input_A = inputdata.getnextasint(); 
unsigned int input_B = inputdata.getnextasint(); 

/* Try to find the specified point in the main point list */
Plist *Anode = find_matching_pnum(input_A, allpoints);
Plist *Bnode = find_matching_pnum(input_B, allpoints);

/* If not in main list, check red list */
if (!Anode) Anode = useredlist(input_A, Anode, redpoints);
if (!Bnode) Bnode = useredlist(input_B, Bnode, redpoints);


/* Still not valid? Must be undefined - error */
if ( !(Anode) || !(Bnode))
  { cerr << "error: point number ";
    if (!Anode) cerr << input_A;
    if ( !(Anode) && !(Bnode) ) cerr << ", ";
    if (!Bnode) cerr << input_B;
    cerr << " undefined\n"; break; }


/* The line is good - go ahead and add it to the line list */
lines = addline(Anode, Bnode, input_A, input_B, lines);

break; } /* End case of 2 number input (line by pnums) */

/* Function to handle data in 3 part format (tri by pnums) */
case 3: {
unsigned int input_A = inputdata.getnextasint(); 
unsigned int input_B = inputdata.getnextasint(); 
unsigned int input_C = inputdata.getnextasint(); 

/* Try to find the specified point in the main point list */
Plist *Anode = find_matching_pnum(input_A, allpoints);
Plist *Bnode = find_matching_pnum(input_B, allpoints);
Plist *Cnode = find_matching_pnum(input_C, allpoints);

/* If not in main list, check red list */
if (!Anode) Anode = useredlist(input_A, Anode, redpoints);
if (!Bnode) Bnode = useredlist(input_B, Bnode, redpoints);
if (!Cnode) Cnode = useredlist(input_C, Cnode, redpoints);

/* Still not valid? Must be undefined - error */
if ( !(Anode) || !(Bnode) || !(Cnode) )
  { cerr << "error: tri vertex point number ";
    if (!Anode) cerr << input_A;
    if ( !(Anode) && !(Bnode) ) cerr << ", ";
    if (!Bnode) cerr << input_B;
    if ( !(Bnode) && !(Cnode) ) cerr << ", ";
    if (!Cnode) cerr << input_C;
    cerr << " undefined\n"; break; }


/* The tri is good - go ahead and add it to the tri list */
 tris = addtri(Anode, Bnode, Cnode, input_A, input_B, input_C, tris);

/* If supplied data is only trifaces (set with -f flag) then we should */
/* add some lines to the database for each tri */
if (the_camera.trilines()){
lines = addline(Anode, Bnode, 0, 0, lines);
lines = addline(Bnode, Cnode, 0, 0, lines);
lines = addline(Cnode, Anode, 0, 0, lines);
}

break; } /* End case of 3 number input (tri by pnums) */

/* Function to handle data in 4 part format */
/* IDnumber , X , Y , Z */
case 4:{
unsigned int input_pnum; 
Vector input_pvector;

/* Load the point's ID number */
input_pnum = inputdata.getnextasint(); 
/* Load the point itself */
input_pvector = getnextasvector(inputdata);

Plist *twicedefined;
Redlist *twicedefinedinR;

/* Check if this point's LOCATION is already here i.e. redundant */
twicedefined = find_matching_vector(input_pvector, allpoints);
if (twicedefined)
/* This vector has been defined somewhere already - try to use it */
{ cerr << "Warning: Point " << input_pnum 
       << " location previously specified ";
     if ( twicedefined->querypnum() ) 
        cerr << "by " << twicedefined->querypnum();
  else  cerr << "as " << twicedefined->querypoint();
        cerr << "." << endl;

/* If the vector matches AND the pnum as well - 100% redundant */
if ( twicedefined->querypnum() == input_pnum )
  { cerr << " Completely redundant. Ignoring." << endl; continue; }

/* If vector is defined somewhere, but pnum is new... */

/* Check for existence of point number in the redundant list */
twicedefinedinR = find_matching_pnum_inRED(input_pnum, redpoints);
if (twicedefinedinR)
{ /* Vector is in point list and pnum is somewher in redlist... */
  if ( twicedefinedinR->querylink() == twicedefined )
{  cerr << "Optimizing." ;
   cerr << " Redundantly defined more than once.";
   cerr << " Ignoring." << endl;
   continue; }

/* if we're here, then the vector was in the list, the pnum wasn't */
/* associated with it, but the pnum was in the red list, but pointing to */
/* something else. Now it needs to be updated. Users who do this */
/* should get their asses kicked! */
  
cerr << "Updating. ";
cerr << input_pnum << " redundantly defined earlier as ";
cerr << twicedefinedinR->querylink()->querypoint();

twicedefinedinR->setup(input_pnum, input_pvector, twicedefined); 

cerr << " now " << twicedefinedinR->querylink()->querypoint() << endl;
continue;
}

/* Vector is in point list - pnum is new... add a new redundant node */
redpoints = 
     addREDpoint( input_pnum, input_pvector, twicedefined, redpoints );

continue; } /* End if Vector is already represented in list */

/* If this is a vector that's new to our data... */

/* Check for existence of point's NUMBER already among all points */
twicedefined = find_matching_pnum(input_pnum, allpoints);
if (twicedefined)
{
 cerr << "Warning: Point identifier previously specified." << endl;
  cerr << "Point #" << twicedefined->querypnum() << " was " 
       << twicedefined->querypoint() << ".";

  twicedefined->setup( twicedefined->querypnum(),
                       input_pvector,
                       twicedefined->querylink()  );

  cerr << " Updated to " << input_pvector << "." << endl;
continue;
}

/* The vector is new */
/* Check for existence of point number in the redundant list */
twicedefinedinR = find_matching_pnum_inRED(input_pnum, redpoints);
if (twicedefinedinR)
{
 /* add a node with this data */
/*  cout << "...adding point:0 - " << input_pvector << endl; */
 allpoints = addpoint(0, input_pvector, allpoints);

 cerr << "warning: Point identifier previously specified. ";
/* Fix redlist to have this existing pnum point to the new point */

twicedefinedinR->setup(input_pnum, input_pvector, allpoints);

  cerr << " Point #" << input_pnum << " is now " 
       << input_pvector << "." << endl;
continue;
}

/* Simply add point which has no redundancy problems */
/* add a node with this data */
/* cout << "...adding point:" << input_pnum << " - " << input_pvector << endl; */
 allpoints = addpoint(input_pnum, input_pvector, allpoints);
continue;

break; } /* End case of 4 number input */

case 6:{
Vector input_pvectorA, input_pvectorB;
Plist *Anode, *Bnode;

/* Load the first point */
input_pvectorA = getnextasvector(inputdata);
/* Load the second point */
input_pvectorB = getnextasvector(inputdata);

/* Is Vector A in the point list? */
Anode = find_matching_vector(input_pvectorA, allpoints);

/* If the point isn't already there, add it (pnum=0) */
if (!Anode) {
/* cout << "...adding point:0" << " - " << input_pvectorA << endl; */
 allpoints = addpoint( 0, input_pvectorA, allpoints);
 Anode = allpoints; } /* now A is good as last added */

/* Is Vector B in the point list? */
Bnode = find_matching_vector(input_pvectorB, allpoints);

/* If the point isn't already there, add it (pnum=0) */
if (!Bnode) {
/* cout << "...adding point:0" << " - " << input_pvectorB << endl; */
 allpoints = addpoint( 0, input_pvectorB, allpoints);
 Bnode = allpoints; } /* now B is good as last added */

/* Go ahead and add the line now */
lines = addline(Anode, Bnode, 0, 0, lines);

break; } /* End case of 6 number input */

case 9:{
Vector input_pvectorA, input_pvectorB, input_pvectorC;
Plist *Anode, *Bnode, *Cnode;

/* Load the first point */
input_pvectorA = getnextasvector(inputdata);
/* Load the second point */
input_pvectorB = getnextasvector(inputdata);
/* Load the third point */
input_pvectorC = getnextasvector(inputdata);

/* Is Vector A in the point list? */
Anode = find_matching_vector(input_pvectorA, allpoints);

/* If the point isn't already there, add it (pnum=0) */
if (!Anode) {
/* cout << "...adding point:0" << " - " << input_pvectorA << endl; */
 allpoints = addpoint( 0, input_pvectorA, allpoints);
 Anode = allpoints; } /* now A is good as last added */

/* Is Vector B in the point list? */
Bnode = find_matching_vector(input_pvectorB, allpoints);

/* If the point isn't already there, add it (pnum=0) */
if (!Bnode) {
/* cout << "...adding point:0" << " - " << input_pvectorB << endl; */
 allpoints = addpoint( 0, input_pvectorB, allpoints);
 Bnode = allpoints; } /* now B is good as last added */

/* Is Vector C in the point list? */
Cnode = find_matching_vector(input_pvectorC, allpoints);

/* If the point isn't already there, add it (pnum=0) */
if (!Cnode) {
/* cout << "...adding point:0" << " - " << input_pvectorC << endl; */
 allpoints = addpoint( 0, input_pvectorC, allpoints);
 Cnode = allpoints; } /* now C is good as last added */

/* Go ahead and add the tri now */
tris = addtri(Anode, Bnode, Cnode, 0, 0, 0, tris);


/* If supplied data is only trifaces (set with -f flag) then we should */
/* add some lines to the database for each tri */
if (the_camera.trilines()){
lines = addline(Anode, Bnode, 0, 0, lines);
lines = addline(Bnode, Cnode, 0, 0, lines);
lines = addline(Cnode, Anode, 0, 0, lines);
}


break; } /* End case of 9 number input */

default:
{ cerr << "error: bad number of input fields." << endl;
  cerr << "wordcount:" << inputdata.wordcount() << endl;
  }

} /* End swtich possible types of input */

} /* End while - until end of line and complete file is read */

} /* End for- look at each file specified loop */


/* ----------------------------- */
/* The data is now in the house! */
/* ----------------------------- */

/* the_camera.campoint(), the_camera.tarpoint(), the_camera.aratio(), */
/* the_camera.zoom(), the_camera.roll(), the_camera.hlr() */

Plist *listindex=allpoints;
while ( listindex )
{ setupview(listindex, the_camera);
  listindex = listindex->querylink(); }

/* Optimization 3: Cull shallow lines - if a line has endpoints common to */
/* 2 trifaces and those trifaces are < a given angle, don't show that */
/* line (unless it's an edge that needs to be viewed) */
if ( the_camera.shallowcull() != 180 )
lines = shallowanglecull( lines, tris,
                     the_camera.shallowcull(), the_camera.hidscolor() );

/* ======= if not hlr, then do the simple printing here. */
if (the_camera.hlr()) 
{ /* After view is properly aligned, the HLR routine can make adjustments */
lines = hlr(allpoints, lines, tris, the_camera);
}
else
{ /* Actually print the raw list right here and now */
Llist *Llistindex=lines;
while ( Llistindex )
{ cout << "line " << Llistindex << endl;
  Llistindex = Llistindex->querylink(); } 
}

/* ----------------------------- */
/* Clean up the mess - free mem  */
/* ----------------------------- */
if (lines) kill_entire_Llist(lines); /* Must be before points go! */
if (tris) kill_entire_Tlist(tris); /* Must be before points go! */
if (allpoints) kill_entire_Plist(allpoints);
/* This could/should go right after input stage is done */
if (redpoints) kill_entire_REDlist(redpoints);

return 0; }

/* End of main=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */

/* Function to manipulate each point according to what is requested */
Plist* setupview(Plist *Pnode, camera &c)
{ Vector T = Pnode->querypoint();
  Vector VV = (c.campoint()-c.tarpoint());
/*   float z=c.zoom(), m=VV.gg_magnitude(), ro=c.roll(); */

  T.gg_set2_subtract( c.tarpoint() );
  T.gg_set2_viewvector( VV );
/*   T.gg_set2_perspective( z , m); */
/*   if (ro) T.gg_set2_rotate(ro); */
  Pnode->editpoint( T );
return Pnode; }

/* Look through tri list to check for a dupilcate */
Tlist* searchtrilist
      (Plist *Anode, Plist *Bnode, Plist *Cnode, Tlist *list2search)
{
if (!list2search) return 0; /* don't look at a blank list */
 Tlist *index=list2search; /* so we don't mess up the start pointer */
 while ( index )
 {
  if ( ( Anode == index->queryA() ) &&
       ( Bnode == index->queryB() ) &&
       ( Cnode == index->queryC() ) )  return index;
  else index = index->querylink(); } /* onto the next one */

 return 0;
}

/* Look through line list to check for a dupilcate */
Llist* searchlinelist(Plist *Anode, Plist *Bnode, Llist *list2search)
{ if (!list2search) return 0; /* don't look at a blank list */
 Llist *index=list2search; /* so we don't mess up the start pointer */
while ( index )
{
  if ( ( Anode == index->queryA() ) &&
       ( Bnode == index->queryB() ) )  return index;
  else index = index->querylink(); } /* onto the next one */

 return 0;
}

Redlist* find_matching_pnum_inRED(unsigned int N, Redlist *list2search)
{ if (!list2search) return 0; /* don't look at a blank list */
 Redlist *index=list2search; /* so we don't mess up the start pointer */
while ( index )
{
  if ( N == index->querypnum() ) return index;
  else index = index->queryredlink(); } /* onto the next one */
 return 0;
}

Plist* find_matching_pnum(unsigned int N, Plist *list2search)
{ if (!list2search) return 0; /* don't look at a blank list */
 Plist *index=list2search; /* so we don't mess up the start pointer */
while ( index )
{ if ( N == index->querypnum() ) return index;
  else index = index->querylink(); } /* onto the next one */
 return NULL;
}

/* Search entire linked list for a specific matching vector */
/* This will be used to check for redundant points (maybe more) */
Plist* find_matching_vector(Vector V, Plist *list2search)
{ if (!list2search) return 0; /* don't look at a blank list */
 Plist *index=list2search; /* so we don't mess up the start pointer */
while ( index )
{ if ( V == index->querypoint() ) return index;
  else index = index->querylink(); } /* onto the next one */
return 0;
}

/* Kill the entire point list - i.e. free memory! */
void kill_entire_Plist(Plist *listindex)
{
/*  cout << "Killing point list: "; */
  while ( !listindex->islast() ) {
  Plist *temp=listindex;
  listindex = listindex->querylink();
/*   cout << temp->querypnum() <<  ", "; */
  delete temp; }
/* cout << listindex->querypnum() << endl; */
delete listindex;
return; }

void kill_entire_Llist(Llist *listindex)
{ /*  cout << "Killing line list: "; */
  while ( listindex ) {
  Llist *temp=listindex;
  listindex = listindex->querylink();
/*   cout << temp->querypnumA() << "-" << temp->querypnumB() <<  ", "; */
  delete temp; }
/* cout << listindex->querypnumA() << "-" << listindex->querypnumB() << endl; */
/* delete listindex; */
return; }

void kill_entire_Tlist(Tlist *listindex)
{
/*  cout << "Killing tri list: ";  */
  while ( !listindex->islast() ) {
  Tlist *temp=listindex;
  listindex = listindex->querylink();
/*   cout << temp->querypnumA() << "-" << temp->querypnumB() */
/*        << "-" << temp->querypnumC() <<  ", "; */
  delete temp; }
/* cout << listindex->querypnumA() << "-" << listindex->querypnumB() */
/*      << "-" << listindex->querypnumC() << endl; */
delete listindex;
return; }

void kill_entire_REDlist(Redlist *listindex)
{
/*  cout << "Killing redundant list: "; */
  while ( !listindex->islast() ) {
  Redlist *temp=listindex;
  listindex = listindex->queryredlink();
/*   cout << temp->querypnum() <<  ", "; */
  delete temp; }
/* cout << listindex->querypnum() << endl; */
delete listindex;
return; }

Plist* Plist::querylink()
{ return link; }

Redlist* Redlist::queryredlink()
{ return redlink; }

Llist* Llist::querylink()
{ return link; }

Tlist* Tlist::querylink()
{ return link; }

Vector Plist::querypoint()
{ return P; }

Vector Plist::editpoint(Vector V)
{ P = V; return P; }

Vector Llist::querypointA()
{ return A->querypoint(); }

Vector Llist::querypointB()
{ return B->querypoint(); }

Vector Tlist::querypointC()
{ return C->querypoint(); }

unsigned int Plist::querypnum()
{ return Pnumber; }

Plist* Llist::queryA()
{ return A; }

Plist* Llist::queryB()
{ return B; }

Plist* Tlist::queryC()
{ return C; }

unsigned int Llist::querypnumA()
{ if (A) return A->querypnum(); else return 0; }

unsigned int Llist::querypnumB()
{ if (B) return B->querypnum(); else return 0; }

unsigned int Tlist::querypnumC()
{ if (C) return C->querypnum(); else return 0; }

/* Don't call this on an empty list!! */
bool Plist::islast()
{ if (!link) return 1; else return 0; }

/* Don't call this on an empty list!! */
bool Redlist::islast()
{ if (!redlink) return 1; else return 0; }

/* Don't call this on an empty list!! */
bool Llist::islast()
{ if (!link) return 1; else return 0; }

/* Don't call this on an empty list!! */
/* Hmm, seems like this might work with Llist's - but doesn't... */
bool Tlist::islast()
{ if (!link) return 1; else return 0; }

Vector getnextasvector(cxe_inputline &inputnow)
{ Vector outvec; float tx, ty, tz;
  tx = inputnow.getnextasfloat();
  ty = inputnow.getnextasfloat();
  tz = inputnow.getnextasfloat();
  outvec.gg_set2( tx, ty, tz );
  return outvec;
}

Vector getnextasvector(cxe_finputline &inputnow)
{ Vector outvec; float tx, ty, tz;
  tx = inputnow.getnextasfloat();
  ty = inputnow.getnextasfloat();
  tz = inputnow.getnextasfloat();
  outvec.gg_set2( tx, ty, tz );
  return outvec;
}

Plist::Plist()
{ Pnumber=0; P=Vector(0,0,0); link=NULL; return; }

void Plist::setup(unsigned int pnum, Vector p, Plist *nextone)
{ Pnumber = pnum; P = p; link = nextone; return; }

void Llist::setup(Plist *a, Plist *b, Llist *next)
{ A=a; B=b; link=next; return;}

void Llist::setupA(Plist *a)
{ A=a; return;}

void Llist::setupB(Plist *b)
{ B=b; return;}

void Llist::setlink(Llist *l)
{ link=l; return; }

void Tlist::setup(Plist *a, Plist *b, Plist *c, Tlist *next)
{ A=a; B=b; C=c; link=next; return;}

void Tlist::setlink(Tlist *l)
{ link=l; return; }

void Plist::linkredirect(Plist *nextone)
{ link = nextone; return; }

/* This function is to output Lines in the X Y format */
/* This is the whole point of the excercise */
void Llist::printXY(ostream *os)
{ Plist *a, *b;
  a=queryA(); b=queryB();
  Vector av, bv;
  av=a->querypoint();  bv=b->querypoint();
 *os <<  av.gg_valX() << "," << av.gg_valY()
     << " " << bv.gg_valX() << "," << bv.gg_valY();
 }

ostream &operator<<(ostream &os, Llist *L)
{ L->printXY(&os); return os; }

Plist* addpoint(unsigned int N, Vector P, Plist *prev)
{ Plist *now;
  now = new Plist;
  now->setup(N, P, prev); 
  return now;
}

Llist* addline(Plist *A, Plist *B,
    unsigned int iA, unsigned int iB, Llist *prev)
{ /* Final checks */
/* Check to see if the line is really a point */
if (A == B)
{ cerr << "error: line consists of two identical points. ";
  cerr << "Ignoring:" << iA << "-" << iB << endl;
  return prev; }

/* Check if this line is already exactly defined with A and B */
/* Don't forget to check for B to A and A to B */
if ( searchlinelist(A, B, prev) || 
     searchlinelist(B, A, prev) )
{ cerr << "error: line already defined. Ignoring extra:"
        << iA << "-" << iB << endl;
   return prev; }

  Llist *now;
  now = new Llist;
  now->setup(A, B, prev); 

/*
      cout << "...Ok...Just made line:"; 
     if ( now->querypnumA() ) 
        cout << now->querypnumA(); else  cout << now->querypointA();
     cout << "-" ;
     if ( now->querypnumB() ) 
        cout << now->querypnumB(); else  cout << now->querypointB();
     cout << endl; 
*/

  return now;
}

Tlist* addtri(Plist *A, Plist *B, Plist *C,
  unsigned int iA, unsigned int iB, unsigned int iC, Tlist *prev)
{

/* Check to see if the tri is really a line or even a point */
if ( (A == B) || (A == C) || (B == C) )
{ cerr << "error: tri consists of two identical points. ";
  cerr << "Ignoring:"
        << iA << "-" << iB << "-" << iC << endl;
  return prev; }

/* Check if this tri is already exactly defined with A, B and C */
/* Hmm, I can't see how to avoid these 6 checks to catch all */
/* permutations. They should go quick though since typically, it */
/* will make one check and move on. */
if ( searchtrilist(A, B, C, prev) ||
     searchtrilist(A, C, B, prev) ||
     searchtrilist(B, A, C, prev) ||
     searchtrilist(B, C, A, prev) ||
     searchtrilist(C, A, B, prev) ||
     searchtrilist(C, B, A, prev) )
{ cerr << "error: tri already defined. Ignoring extra:"
        << iA << "-" << iB << "-" << iC << endl;
   return prev; }

 Tlist *now;
  now = new Tlist;
  now->setup(A, B, C, prev); 

/*
     cout << "...Ok...Just made tri:";
     if ( now->querypnumA() ) 
        cout << now->querypnumA(); else  cout << now->querypointA();
     cout << "-" ;
     if ( now->querypnumB() ) 
        cout << now->querypnumB(); else  cout << now->querypointB();
     cout << "-" ;
     if ( now->querypnumC() ) 
        cout << now->querypnumC(); else  cout << now->querypointC();
     cout << endl; 
*/

  return now;
}
  

void Redlist::setredlink(Redlist *R)
{ this->redlink = R; return;}

Redlist* addREDpoint(unsigned int N, Vector P,
                      Plist *shouldbe, Redlist *prev)
{ Redlist *now;
  now = new Redlist;
  now->setup(N, P, shouldbe);
  now->setredlink(prev);
  return now;
}

Plist * useredlist(unsigned int N, Plist *node, Redlist *redpts)
{
/* If the point isn't in the main list check the redundant list */
Redlist *inred = find_matching_pnum_inRED( N, redpts);
/* if (inred) cout << N << " was found in redlist!\n"; */
/* If the point is in the redundant list, use it's reference */
if (inred)
  node = inred->querylink();
/* If the piont is neither in the list or redlist, it's in error */
/*  and will return a null still  */
return node;
}

/* Option processing routine */
void dealwithoptions(int optc,char **optv, camera &initcam)
{ int o;
  initcam.hlr_off(); /* Set the default here to off */
  initcam.trilines_off(); /* Set the default here to off */
  initcam.shallowcull(180); /* Default shallow cull to off = 180 */
  initcam.hidscolor("off"); /* Default hidscolor to off */
  Vector setdefault(0,0,0); initcam.tarpoint( setdefault );
         setdefault.gg_set2(0,0,1); initcam.campoint( setdefault );
  static char optstring[] = "a:c:d:fhop:r:s:t:z:";
  while ( (o = getopt( optc, optv, optstring)) != -1)
   switch (o){
    case 'h' :
     cout << "vmaster - Chris X Edwards" << endl;
     cout << "-a	Aspect ratio <ratio>. NOT DONE!" << endl;
     cout << "-c	Camera point <x,y,z>." << endl;
     cout << "-d	Deleted lines visible <color>." << endl;
     cout << "-f	Faces only, fill-in lines." << endl;
     cout << "-h	This help message." << endl;
     cout << "-o	Opacity flag. Hidden line removal." << endl;
     cout << "-p	Pierce point marks <size>." << endl;
     cout << "-r	Camera roll aka twist <angle>." << endl;
     cout << "-s	Shallow surface cull <angle>." << endl;
     cout << "-t	Target point <x,y,z>." << endl;
     cout << "-z	Zoom factor <factor>. NOT DONE!" << endl;
     break;

    case 'a':
     {float t=atof(optarg);
     cout << "# Aspect ratio:" << t << endl;
     initcam.aratio( t ); }
     break;

    case 'c' :
    {
     cxe_inputline initcampoint(optarg);
     initcampoint.stripallbut("0123456789.-eE");
     Vector V=getnextasvector(initcampoint);
     initcam.campoint( V );
     cout << "# Camera point:" << V << endl;
    }
     break;

    case 'd' :
     {initcam.hidscolor(optarg);
     cout << "# Deleted rendered in color " << optarg << endl;
     break;}

    case 'f' :
     { initcam.trilines_on();
     cout << "# Faces only, adding implied lines for tris" << endl;
     break;}

    case 'o' :
     {initcam.hlr_on();
     cout << "# Opacity HLR flag:on\n";
     break;}

    case 'p' :
     {float t=atof(optarg);
     initcam.ppmark(t);
     cout << "# Pierce points marked with pointsize " 
          << initcam.ppmark() << endl;
     break;}

    case 'r' :
     {float t=atof(optarg);
     cout << "# Camera roll:" << t << endl;
     initcam.roll( t );
     break; }

    case 's' :
     {float t=atof(optarg);
      t = t*(M_PI/180); /* Radians */
      cout << "# Shallow cull angle:" << t << endl;
      initcam.shallowcull(t);
      break; }

    case 't' :
     {
     cxe_inputline inittarpoint(optarg);
     inittarpoint.stripallbut("0123456789.-eE");
     Vector V=getnextasvector(inittarpoint);
     initcam.tarpoint( V );
     cout << "# Target point:" << V << endl;
     break; }

    case 'z' :
     {float t=atof(optarg);
     cout << "# Zoom factor:" << t << endl;
     initcam.zoom( t ); 
     break; }

    default :
     cerr << "Unknown option. Use -h for list of valid options.\n";
}  /* End of option processing switch */
return; }

/* Function to check if a triface has any bounding box interference with */
/* a supplied line nodek */
bool Tlist::BBinterfere(Llist *L)
{ 
if (!BBinthelper(  L->querypointA().gg_valX(),
                   L->querypointB().gg_valX(), querypointA().gg_valX(),
                   querypointB().gg_valX(), querypointC().gg_valX() ) )
return 0; /* entities don't share same space on X axis */

if (!BBinthelper(  L->querypointA().gg_valY(),
                   L->querypointB().gg_valY(), querypointA().gg_valY(),
                   querypointB().gg_valY(), querypointC().gg_valY() ) )
return 0; /* entities don't share same space on Y axis */

/* Disable this for now... z separation can still mean obstruction */
/* if (!BBinthelper(  L->querypointA().gg_valZ(), */
/*                    L->querypointB().gg_valZ(), querypointA().gg_valZ(), */
/*                    querypointB().gg_valZ(), querypointC().gg_valZ() ) ) */
/* return 0; */
 /* entities don't share same space on Z axis */

return 1;}

/* Generic boundary component check function (local scope only) */
bool BBinthelper(float lA, float lB, float tA, float tB, float tC )
{ float lmin, lmax, tmin, tmax;
if (lA < lB) {lmin=lA; lmax=lB;} else {lmin=lB; lmax=lA;}  
if (tA < tB) {tmin=tA; tmax=tB;} else {tmin=tB; tmax=tA;}  
if (tC < tmin) { tmin=tC; } else if (tC > tmax) { tmax=tC;}
if (lmin > tmax ) return 0;
if (tmin > lmax ) return 0;
return 1; /* in this axis, they have overlap */
} /* End of generic boundary component check function */


/* Function to check if a triangle is made of 3 points that are colinear */
/* in the xy plane. If this is so, then the triangle can't obscure */
/* anything. It's on edge. */
bool Tlist::trionedge()
{ Vector N, V(0,0,1), /* V is view vector */
         A=querypointA(), B=querypointB(), C=querypointC();
N = (B-A) & (C-A); /* cross 2 sides of tri for normal */
if (N | V) return 0; /* if normal dot view is something then good */
else return 1; /* if N dot V is nothing, then tri is on edge */
}

