// ****************************************************************************
// ****************************************************************************
// ****************************************************************************
//                   V E K T O R K L A S S E    V1.0
//               Written by Jens Thiele in Spetember 1995
// ****************************************************************************
// ****************************************************************************
// ****************************************************************************



// _____________________________________________________________________________
// To Do:
// Punkt in parallelogramm ?
// testen = > universal Testprogramm wird man je alle Routinen benutzt haben ?  
// speedtest und evtl beschleunigen !!
// einen besseren Gauss schreiben (naja fuer 2x2 ist er suppergut !)
// int vektoren ?
// punktauflinie ?
// KNOWN BUGS :
// schneide bei parallele Linien hintereinander (BISJETZT FALSCH !)
// _____________________________________________________________________________



#include "vektor.H"



// ****************************************************************************
// ****************************************************************************
// ****************************************************************************
// ****************************************************************************
//                      P U B L I C - F U N K T I O N E N
// ****************************************************************************
// ****************************************************************************
// ****************************************************************************
// ****************************************************************************


// ********************************** BERECHNET ABSOLUTWERT VON FLOAT
float floatabs(float a)
{
    return((a<0) ? (-a):(a));
};

// Runden !! float als int interpretieren ist FALSCH !!!!!!!!


// 2 Gleichungen, 2 Unbekannte (r,s)
// r*vektor2(a) + s*vektor2(b) = vektor2(c)  
// ________________________________________
// |_____r______|______s_____|____________|
// |   a->x     |    b->x    |    c->x    |
// |   a->y     |    b->y    |    c->y    |
// |____________|____________|____________|

int gauss_dim2(vektor2_koordtype *a,vektor2_koordtype *b,
		vektor2_koordtype *c,float *r,float *s)
{
    // Spezialfall ??
    if ((a->x==0)||(a->y==0)||(b->x==0)||(b->y==0)||((c->x==0)&&(c->y==0)))
	{
	    // Nullzeilen ??? => Unendlich viele oder keine Loesungen
	    if ((a->x==0)&&(b->x==0))
		{
		    if (c->x==0)
			return(-1);
		    else
			return(0);
		}
	    if ((a->y==0)&&(b->y==0))
		{
		    if (c->y==0)
			return(-1);
		    else
			return(0);
		}

	    // Homogenes GS
	    if ((c->x==0)&&(c->y==0))
		{
		    if (((a->x==0)&&(a->y==0))||((b->x==0)&&(b->y==0)))
			{
			    // Nullvektoren enthalten => unendlich viele Lsg.
			    return(-1);
			}
		    // Triviale oder unendlich viele Lsg.
		    if ((a->x/a->y)==(b->x/b->y))
			{
			    // Nullzeile 
			    return(-1);
			}
		    else
			{
			    // Triviale Lsg.
			    *r=0;
			    *s=0;
			    return(1);
			}
		}

	    // Nullvektoren ??? => Gleichungssystem 2 Gleichungen 1 Unbekannte
	    if ((a->x==0)&&(a->y==0))
		{
		    if ( (c->y) && ((b->x/b->y)==(c->x/c->y)) )
			return(-1);
		    return(0);
		}
	    if ((b->x==0)&&(b->y==0))
		{
		    if ( (c->y) && ((a->x/a->y)==(c->x/c->y)) )
			return(-1);
		    return(0);
		}

            // Einsetzen !!!
	    if (a->x==0)
		{
		    *s=c->x / b->x;
		    *r=(c->y - (*s)*b->y)/a->y;
		    return(1);
		}
	    if (b->x==0)
		{
		    *r=c->x / a->x;
		    *s=(c->y - (*r)*a->y)/b->y;
		    return(1);
		}
	    if (a->y==0)
		{
		    *s=c->y / b->y;
		    *r=(c->x - (*s)*b->x)/a->x;
		    return(1);
		}
	    if (b->y==0) // spaeter if weg da bedingung immer erfuellt !
		{
		    *r=c->y / a->y;
		    *s=(c->x - (*r)*a->x)/b->x;
		    return(1);
		}
	    fatalfehler("gauss_dim2: Unmoeglicher Fehler !"); // spaeter
	}
    // Normaler Gauss
    // Eventuell eine Nullzeile ????
    float nenner=b->x * a->y - b->y * a->x;
    if (nenner!=0)
	{
	    *s=(c->x * a->y - c->y * a->x) / nenner;
	    *r=(c->x - (*s)*b->x)/a->x;
	    return(1);
	}
    else
	{
	    if ((a->x*c->y)==(c->x*a->y))
		{
		    // Nullzeile
		    return(-1);
		}
		else
		{
		    // Widerspruch
		    return(0);
		}
	}
}








// ****************************************************************************
// ****************************************************************************
// ****************************************************************************
// ****************************************************************************
//                  K L A S S E N - F U N K T I O N E N
// ****************************************************************************
// ****************************************************************************
// ****************************************************************************
// ****************************************************************************



// ****************************************************************************
// ****************************************************************************
// ****************************************************************************
//                       V E K T O R - O B J E K T E
// ****************************************************************************
// ****************************************************************************
// ****************************************************************************


// ****************************************************************************
// ****************************************************************************
// Koordinaten Vektor:  gut zum addieren, schlecht zum rotieren 
// ****************************************************************************
// ****************************************************************************

vektor2_koordtype::vektor2_koordtype(){}
vektor2_koordtype::vektor2_koordtype(float _x,float _y){import(_x,_y);}
vektor2_koordtype::vektor2_koordtype(const vektor2_koordtype *source){import(source);}
vektor2_koordtype::vektor2_koordtype(const vektor2_poltype *source){import(source);}
vektor2_koordtype::vektor2_koordtype(iotype *ioptr,int8 mode){change(ioptr,mode);};

void vektor2_koordtype::change(iotype *ioptr,int8 mode)
{
    cfgtype *cfgptr=choose_cfgtype(ioptr,mode);
    cfgptr->change_float_check(&x);
    cfgptr->change_float_check(&y);
    delete cfgptr;
}

void vektor2_koordtype::add(const vektor2_koordtype *source)
{
    x+=source->x;
    y+=source->y;
}

void vektor2_koordtype::add(const vektor2_poltype *source)
{
    vektor2_koordtype transformed(source);
    add(&transformed);
}

void vektor2_koordtype::neg()
{
    x=-x;
    y=-y;
}

void vektor2_koordtype::sub(const vektor2_koordtype *source)
{
    x-=source->x;
    y-=source->y;
}

void vektor2_koordtype::sub(const vektor2_poltype *source)
{
    vektor2_koordtype transformed(source);
    sub(&transformed);
}

void vektor2_koordtype::rotate(float rad)
{
    vektor2_poltype transformed(this);
    transformed.rotate(rad);
    import(&transformed);
}

float vektor2_koordtype::betrag() const
{
    return ( sqrt(this->x*this->x+this->y*this->y) );
}

void vektor2_koordtype::import(float _x,float _y)
{
    x=_x;
    y=_y;
}

void vektor2_koordtype::import(const vektor2_koordtype *source)
{
    *this=*source;
}
void vektor2_koordtype::import(const vektor2_poltype *source)
{
    x=cos(source->dir)*source->betrag;
    y=sin(source->dir)*source->betrag;
}

vektor2_koordtype operator+(const vektor2_koordtype &v1,const vektor2_koordtype &v2)
{
  vektor2_koordtype erg(&v1);
  erg.add(&v2);
  return erg;
}
ostream &operator<<(ostream &ost,const vektor2_koordtype &v)
{
  ost << v.x <<" "<<v.y;
  return ost;
}
istream &operator>>(istream &ist,vektor2_koordtype &v)
{
  ist >> v.x >>v.y;
  return ist;
}


// ****************************************************************************
// ****************************************************************************
// Pol-Vektor:  gut zum rotieren, schlecht zum addieren 
// ****************************************************************************
// ****************************************************************************

vektor2_poltype::vektor2_poltype(){};
vektor2_poltype::vektor2_poltype(float _betrag,float _dir){import(_betrag,_dir);}
vektor2_poltype::vektor2_poltype(const vektor2_poltype *source){import(source);}
vektor2_poltype::vektor2_poltype(const vektor2_koordtype *source){import(source);}
vektor2_poltype::vektor2_poltype(iotype *ioptr,int8 mode){change(ioptr,mode);}

void vektor2_poltype::change(iotype *ioptr,int8 mode)
{
    // Laden ******************************************************************
    if (ioptr->getmode()==IOTYPE_READ_MODE)
	{
	    vektor2_koordtype loader;
	    loader.change(ioptr,mode);
	    import(&loader);
	    return;
	}
    // Speichern **************************************************************
    vektor2_koordtype saver(this);
    saver.change(ioptr,mode);
}

void vektor2_poltype::add(const vektor2_poltype *source)
{
    vektor2_koordtype sourcetransformed(source);
    add(&sourcetransformed);
}

void vektor2_poltype::add(const vektor2_koordtype *source)
{
    vektor2_koordtype desttransformed(this);
    desttransformed.add(source);
    import(&desttransformed);
}

void vektor2_poltype::neg()
{
    betrag=-betrag;
}

void vektor2_poltype::sub(const vektor2_poltype *source)
{
    vektor2_koordtype sourcetransformed(source);
    sub(&sourcetransformed);    
}

void vektor2_poltype::sub(const vektor2_koordtype *source)
{
    vektor2_koordtype desttransformed(this);
    desttransformed.sub(source);
    import(&desttransformed);
}

void vektor2_poltype::rotate(float rad)
{
    dir+=rad;
}

void vektor2_poltype::import(float _betrag,float _dir)
{
    betrag=_betrag;
    dir=_dir;
}

void vektor2_poltype::import(const vektor2_koordtype *source)
{
    betrag=source->betrag();
    dir=atan2(source->y,source->x);
}

void vektor2_poltype::import(const vektor2_poltype *source)
{
    *this=*source;
}






// ****************************************************************************
// ****************************************************************************
// ****************************************************************************
//                     L I N I E N - O B J E K T E
// ****************************************************************************
// ****************************************************************************
// ****************************************************************************


// ****************************************************************************
// ****************************************************************************
//  Linie mit Startpunkt und Endpunkt in Koordinatenform !
//  Einfach zum Eingeben !   Nicht zum Rechnen !
// ****************************************************************************
// ****************************************************************************
linie2_koordpunkt_koordpunkttype::linie2_koordpunkt_koordpunkttype(){}
linie2_koordpunkt_koordpunkttype::linie2_koordpunkt_koordpunkttype(
								   float _x1,float _y1,float _x2,float _y2)
{import(_x1,_y1,_x2,_y2);}
linie2_koordpunkt_koordpunkttype::linie2_koordpunkt_koordpunkttype
(const vektor2_koordtype *_startp,const vektor2_koordtype *_endp)
{
  import(_startp,_endp);
}
linie2_koordpunkt_koordpunkttype::linie2_koordpunkt_koordpunkttype
(const linie2_koordpunkt_koordpunkttype *source)
{
  import(source);
}
linie2_koordpunkt_koordpunkttype::linie2_koordpunkt_koordpunkttype
(const linie2_koordpunkt_koorddirtype *source)
{
  import(source);
}
linie2_koordpunkt_koordpunkttype::linie2_koordpunkt_koordpunkttype
(const linie2_polpunkt_poldirtype *source)
{
  import(source);
}
linie2_koordpunkt_koordpunkttype::linie2_koordpunkt_koordpunkttype(iotype *ioptr,int8 mode)
{change(ioptr,mode);}

void linie2_koordpunkt_koordpunkttype::change(iotype *ioptr,int8 mode)
{
    startp.change(ioptr,mode);
    endp.change(ioptr,mode);
}

void linie2_koordpunkt_koordpunkttype::rotate(float rad)
{
    startp.rotate(rad);
    endp.rotate(rad);
}

int linie2_koordpunkt_koordpunkttype::schneide
(const linie2_koordpunkt_koordpunkttype &source,vektor2_koordtype *sp)
{
    linie2_koordpunkt_koorddirtype sourcetransformed(&source);
    return schneide(sourcetransformed,sp);
}

int linie2_koordpunkt_koordpunkttype::schneide
(const linie2_koordpunkt_koorddirtype &source,vektor2_koordtype *sp)
{
    linie2_koordpunkt_koorddirtype desttransformed(this);
    return desttransformed.schneide(source,sp);
}

int linie2_koordpunkt_koordpunkttype::schneide
(const linie2_polpunkt_poldirtype &source,vektor2_koordtype *sp)
{
    linie2_koordpunkt_koorddirtype sourcetransformed(&source);
    return schneide(sourcetransformed,sp);
}

void linie2_koordpunkt_koordpunkttype::import
(float _x1,float _y1,float _x2,float _y2)
{
    startp.x=_x1;
    startp.y=_y1;
    endp.x=_x2;
    endp.y=_y2;
}

void linie2_koordpunkt_koordpunkttype::import
(const vektor2_koordtype *_startp,const vektor2_koordtype *_endp)
{
    startp=*_startp;
    endp=*_endp;
}

void linie2_koordpunkt_koordpunkttype::import
(const linie2_koordpunkt_koordpunkttype *source)
{
    *this=*source;
}

void linie2_koordpunkt_koordpunkttype::import
(const linie2_koordpunkt_koorddirtype *source)
{
    startp=source->startp;
    endp=startp;
    endp.add(&(source->richtung));
}

void linie2_koordpunkt_koordpunkttype::import
(const linie2_polpunkt_poldirtype *source)
{
    startp.import(&(source->startp));
    endp=startp;
    endp.add(&(source->richtung));
}


// ****************************************************************************
// ****************************************************************************
//  Linie mit Startpunkt und Richtungsvektor in Koordinatenform !
//  Relativ einfach zum Eingeben und gut zum Schneiden !!!! schlecht zum Drehen
// ****************************************************************************
// ****************************************************************************
linie2_koordpunkt_koorddirtype::linie2_koordpunkt_koorddirtype(){}
linie2_koordpunkt_koorddirtype::linie2_koordpunkt_koorddirtype
(const vektor2_koordtype *_startp,const vektor2_koordtype *_richtung)
{
  import(_startp,_richtung);
}
linie2_koordpunkt_koorddirtype::linie2_koordpunkt_koorddirtype
(const linie2_koordpunkt_koordpunkttype *source)
{
  import(source);
}
linie2_koordpunkt_koorddirtype::linie2_koordpunkt_koorddirtype
(const linie2_koordpunkt_koorddirtype *source)
{
  import(source);
}
linie2_koordpunkt_koorddirtype::linie2_koordpunkt_koorddirtype
(const linie2_polpunkt_poldirtype *source)
{
  import(source);
}
linie2_koordpunkt_koorddirtype::linie2_koordpunkt_koorddirtype(iotype *ioptr,int8 mode)
{change(ioptr,mode);}


void linie2_koordpunkt_koorddirtype::change(iotype *ioptr,int8 mode)
{
    // LADEN ******************************************************************
    if (ioptr->getmode()==IOTYPE_READ_MODE)
	{
	    linie2_koordpunkt_koordpunkttype loader;
	    loader.change(ioptr,mode);
	    import(&loader);
	    return;
	}
    // SPEICHERN **************************************************************
    linie2_koordpunkt_koordpunkttype saver(this);
    saver.change(ioptr,mode);
}

void linie2_koordpunkt_koorddirtype::rotate(float rad)
{
    startp.rotate(rad);
    vektor2_poltype polrichtung(&richtung);
    polrichtung.rotate(rad);
    richtung.import(&polrichtung);
};



int linie2_koordpunkt_koorddirtype::schneide
(const linie2_koordpunkt_koordpunkttype &source,vektor2_koordtype *sp)
{
    linie2_koordpunkt_koorddirtype sourcetransformed(&source);
    return schneide(sourcetransformed,sp);
}

// Rueckgabewert 0=keine-,1=eine-,-1=unendlich viele Loesungen
// Gleichungssytem: 2 Gleichungen 2 Unbekannte
//          a          |         b            |  
//   this->richtung    |  - source->richtung  |  source->startp - this->startp

int linie2_koordpunkt_koorddirtype::schneide
(const linie2_koordpunkt_koorddirtype &source,vektor2_koordtype *sp)
{
    vektor2_koordtype bv(-source.richtung.x,-source.richtung.y);
    vektor2_koordtype c(source.startp);
    c.x-=startp.x;
    c.y-=startp.y;
    float a;
    float b;
    int erg=gauss_dim2(&richtung,&bv,&c,&a,&b);
    // Ein Schnittpunkt
    if (erg==1)
	{
	    // Schnittpunkt in beiden Linien enthalten ??
	    if ((a>=0)&&(a<=1)&&(b>=0)&&(b<=1))
		{
		    sp->x=startp.x+ a * richtung.x;
		    sp->y=startp.y+ a * richtung.y;
		    return(1);
		}
	    return(0);
	}
    else
      if (erg==-1)
	{
	  // Unendliche viele Loesungen => Linien parallel hintereinander
	  cout <<"Linien beim Schneiden parallel\n";
	  float r;
	  float t1;
	  float t2;
	  if (floatabs(richtung.y)>floatabs(richtung.x))
	    {
	      r=richtung.y;
	      t1=(startp.y-source.startp.y)/r;
	      t2=(startp.y-source.startp.y-source.richtung.y)/r;
	    }
	  else
	    {
	      r=richtung.x;
	      t1=(startp.x-source.startp.x)/r;
	      t2=(startp.x-source.startp.x-source.richtung.x)/r;
	    }
	  if (((t1>=0.0)&&(t1<=1.0))||((t2>=0.0)&&(t2<=1.0)))
	    // Einer der beiden punkte der anderen Linie ist enthalten
	    return -1;
	  if (((t1<0.0)&&(t2>1.0))||((t2<0.0)&&(t1>1.0)))
	    // andere Linie "umschliesst" die Linie
	    return -1;
	  // Kann kein Schnittpunkt haben
	}
    return(0);
}

int linie2_koordpunkt_koorddirtype::schneide
(const linie2_polpunkt_poldirtype &source,vektor2_koordtype *sp)
{
    linie2_koordpunkt_koorddirtype sourcetransformed(&source);
    return schneide(sourcetransformed,sp);
}

/*int linie2_koordpunkt_koorddirtype::punktauflinie(vektor2_koordtype punkt)
{
    punkt.sub(&startp);
    float k1=punkt.x/richtung.x;
    float k2=punkt.y/richtung.y;
    if (k1!=k2)
	return(0);
    jens
    return(1);
}
*/

void linie2_koordpunkt_koorddirtype::import
(const vektor2_koordtype *_startp,const vektor2_koordtype *_richtung)
{
    startp=*_startp;
    richtung=*_richtung;
}

void linie2_koordpunkt_koorddirtype::import
(const linie2_koordpunkt_koordpunkttype *source)
{
    startp=source->startp;
    richtung=source->endp;
    richtung.sub(&startp);
}

void linie2_koordpunkt_koorddirtype::import
(const linie2_koordpunkt_koorddirtype *source)
{
    *this=*source;
}

void linie2_koordpunkt_koorddirtype::import
(const linie2_polpunkt_poldirtype *source)
{
    startp.import(&(source->startp));
    richtung.import(&(source->richtung));
}


// ****************************************************************************
// ****************************************************************************
//  Linie mit Startpunkt und Richtungsvektor in Pol-Koordinatenform !
//  Schlecht zum Eingeben, gut zum Drehen, schlecht zum Schneiden
// ****************************************************************************
// ****************************************************************************


linie2_polpunkt_poldirtype::linie2_polpunkt_poldirtype(){}
linie2_polpunkt_poldirtype::linie2_polpunkt_poldirtype(
						       const vektor2_poltype *_startp,const vektor2_poltype *_richtung)
{
  import(_startp,_richtung);
}
linie2_polpunkt_poldirtype::linie2_polpunkt_poldirtype(
						       const linie2_koordpunkt_koordpunkttype *source)
{
  import(source);
}
linie2_polpunkt_poldirtype::linie2_polpunkt_poldirtype
(const linie2_koordpunkt_koorddirtype *source)
{
  import(source);
}
linie2_polpunkt_poldirtype::linie2_polpunkt_poldirtype
(const linie2_polpunkt_poldirtype *source)
{
  import(source);
}
linie2_polpunkt_poldirtype::linie2_polpunkt_poldirtype(iotype *ioptr,int8 mode)
{change(ioptr,mode);}



void linie2_polpunkt_poldirtype::change(iotype *ioptr,int8 mode)
{
    // LADEN ******************************************************************
    if (ioptr->getmode()==IOTYPE_READ_MODE)
	{
	    linie2_koordpunkt_koordpunkttype loader;
	    loader.change(ioptr,mode);
	    import(&loader);
	    return;

	}
    // SPEICHERN **************************************************************
    linie2_koordpunkt_koordpunkttype saver(this);
    saver.change(ioptr,mode);
}

void linie2_polpunkt_poldirtype::rotate(float rad)
{
    startp.rotate(rad);
    richtung.rotate(rad);
}

int linie2_polpunkt_poldirtype::schneide
(const linie2_koordpunkt_koordpunkttype &source,vektor2_koordtype *sp)
{
    linie2_koordpunkt_koorddirtype sourcetransformed(&source);
    return schneide(sourcetransformed,sp);
}

int linie2_polpunkt_poldirtype::schneide
(const linie2_koordpunkt_koorddirtype &source,vektor2_koordtype *sp)
{
    linie2_koordpunkt_koorddirtype desttransformed(this);
    return desttransformed.schneide(source,sp);
}

int linie2_polpunkt_poldirtype::schneide
(const linie2_polpunkt_poldirtype &source,vektor2_koordtype *sp)
{
    linie2_koordpunkt_koorddirtype sourcetransformed(&source);
    return schneide(sourcetransformed,sp);    
}

void linie2_polpunkt_poldirtype::import
(const vektor2_poltype *_startp,const vektor2_poltype *_richtung)
{
    startp=*_startp;
    richtung=*_richtung;
}

void linie2_polpunkt_poldirtype::import
(const linie2_koordpunkt_koordpunkttype *source)
{
    startp.import(&(source->startp));
    vektor2_koordtype koordrichtung(source->endp);
    koordrichtung.sub(&(source->startp));
    richtung.import(&koordrichtung);
}

void linie2_polpunkt_poldirtype::import
(const linie2_koordpunkt_koorddirtype *source)
{
    startp.import(&(source->startp));
    richtung.import(&(source->richtung));
}

void linie2_polpunkt_poldirtype::import
(const linie2_polpunkt_poldirtype *source)
{
    *this=*source;
}




















