/*
* Filename: D:\Studienarbeit\Beispiel2\Beispiel2.cpp
* Version: 1.0
* Date: Tue Sept 8
* Author: junge
*/

#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#endif /*WIN32*/

#ifdef __linux
#include <typeinfo>
#else
#include <typeinfo.h>
#endif

#include <stdio.h>
#include <stdlib.h>


#include <tcl.h>
#include <tk.h>
#include <math.h>


#ifndef M_PI
#define M_PI        3.14159265358979323846
#endif

#define FAKT  30
#define YNULL 34           //*** Korrektur fuer y-Nullpunkt (Scrollbar...)
#define XNULL 2            //***        "       x-Nullpunkt       "


float g_xmax = 0.0;
float g_ymax = 0.0;


char gWindow[50];

struct primitive
{
	float x1;
	float x2;
	float y1;
	float y2;
};

struct segmente
{
	float xSeg0;
	float ySeg0;
	int angle;
	int linezaehler;
	struct primitive lines [10];		
	
};


struct segmente segment[50]; 	//50 Segmente muessten erstmal genuegen


int SegNr = 0;
int SegAnzahl = 0;

Tk_TimerToken timerToken = NULL;
Tcl_Interp *MainInterp = NULL;


char farbe[] = "blue     ";




//*************************************************************************
//********** Grafikfenster erzeugen
//*************************************************************************
void erzeugeFenster(float xGr, float yGr, char *Col)
{
    char buf[1000];

    g_xmax = xGr * FAKT;
    g_ymax = yGr * FAKT;

    sprintf (buf,
      "toplevel .gWin; frame .gWin.cf -relief ridge -borderwidth 4; "
      "canvas .gWin.cf.c -width %d -height %d -relief sunken "
      " -yscrollcommand \".gWin.cf.scrolly set\" "
      " -xscrollcommand \".gWin.cf.scrollx set\"; "
      "scrollbar .gWin.cf.scrolly -command \".gWin.cf.c yview\"; "
      "scrollbar .gWin.cf.scrollx -orient horizontal"
      " -command \".gWin.cf.c xview\"; "
      "pack .gWin.cf.scrolly -side right -fill y; "
      "pack .gWin.cf.scrollx -side bottom -fill x; "
      "pack .gWin.cf .gWin.cf.c -expand yes -fill both; "
      "wm geometry .gWin %dx%d; wm maxsize .gWin %d %d; "
      "wm minsize .gWin %d %d; tkwait visibility .gWin; ",
      (int)g_xmax, (int)g_ymax,
      (int)g_xmax, (int)g_ymax,
      (int)g_xmax, (int)g_ymax,
       0, 0);
    Tcl_Eval (MainInterp,buf);
        
    sprintf (buf, ".gWin.cf.c configure -background %s ; ",
                  Col);
    Tcl_Eval (MainInterp,buf);
    sprintf (gWindow, ".gWin.cf.c");
    
}


//*************************************************************************
//********** Grafikausgabe updaten (flush) 
//*************************************************************************
void flush ()
{
  char buf[10];
  sprintf(buf, "update;");
  Tcl_Eval(MainInterp, buf);
}

//*************************************************************************
//********** Segment erzeugen
//*************************************************************************
int erzeugeSegment (float x, float y)
{


    SegNr++;
    char buf[256];
    segment[SegNr].linezaehler = 0;
    segment[SegNr].xSeg0 = x;
    segment[SegNr].ySeg0 = y;
    sprintf  (buf,"set tag%d; ",SegNr);
    Tcl_Eval (MainInterp, buf);
    return SegNr;

}



//*************************************************************************
//********** Linie zum Segment
//*************************************************************************
void line(int seg, float x1, float y1, float x2, float y2)
{
  char buf[256];


  segment[seg].linezaehler++;
  
  segment[seg].lines[segment[seg].linezaehler].x1 = x1;
  segment[seg].lines[segment[seg].linezaehler].y1 = y1;
  segment[seg].lines[segment[seg].linezaehler].x2 = x2;
  segment[seg].lines[segment[seg].linezaehler].y2 = y2;
  
  x1 = segment[seg].xSeg0 + x1;
  y1 = segment[seg].ySeg0 + y1;
  x2 = segment[seg].xSeg0 + x2;
  y2 = segment[seg].ySeg0 + y2;


  float x1_ = XNULL + (x1 * FAKT);             //*** Zum Zeichnen umrechn.
  float y1_ = (g_ymax - YNULL) - (y1 * FAKT);
  float x2_ = XNULL + (x2 * FAKT);
  float y2_ = (g_ymax - YNULL) - (y2 * FAKT);
  
  
  sprintf(buf,"%s create line %6.2f %6.2f %6.2f %6.2f -fill %s -tag tag%d; "
              , gWindow, x1_, y1_, x2_, y2_, farbe, seg);
  Tcl_Eval (MainInterp, buf);
}

//*************************************************************************
//********** Segment (relativ) bewegen
//*************************************************************************
void bewegeSegment (int seg, float dx, float dy)
{
  char buf[256];
  
  float phi_g = segment[seg].angle % 360;
  float phi = phi_g * M_PI / 180.0;
  
  float x = dx * cos (phi) - dy * sin (phi);
  float y = dx * sin (phi) + dy * cos (phi);
  
  segment[seg].xSeg0 += x;
  segment[seg].ySeg0 += y;
  
  x *= FAKT;
  y *= FAKT;
  sprintf (buf,"%s move tag%d %6.2f %6.2f;",
              gWindow, seg, x, -y);
  Tcl_Eval (MainInterp, buf);
}
//*************************************************************************
//********** Segment loeschen (Tag und Daten im Struct bleiben bestehen)
//*************************************************************************
void loescheSegment (int seg) 
{
  char buf[256]; 
  sprintf  (buf,"%s delete tag%d;",gWindow, seg, seg);
  Tcl_Eval (MainInterp, buf);   
}

//*************************************************************************
//********** Text zum Segment 
//*************************************************************************
void schreibetext(float x, float y, float text)
{
  char buf[256];
  float x1 = x; 
  float y1 = y;
  float x1_ = XNULL + (x1 * FAKT);             //*** Zum Zeichnen umrechn.
  float y1_ = (g_ymax - YNULL) - (y1 * FAKT);
    
  sprintf(buf, "%s create text %6.2f %6.2f -tag tag%d -text %6.2f -fill %s"
               , gWindow, x1_, y1_, 100, text, farbe);
  Tcl_Eval (MainInterp, buf);
}

//*************************************************************************
//********** Segment um Ursprung des segmenteigenen Koord.-system drehen
//*************************************************************************
void dreheSegment (int seg, int angle) 
{ 
  float x1neu, x2neu, y1neu, y2neu, phi_g, phi = 0.0;
  char buf[256];
  
  phi_g = angle % 360;
  phi = phi_g * M_PI / 180.0;
  segment[seg].angle += angle;
  
  loescheSegment (seg);

  int max = segment[seg].linezaehler;
  segment[seg].linezaehler = 0; 
  for (int z = 1; z <= max ;z++)
  {
 
  x1neu = (segment[seg].lines[z].x1 * cos (phi) - segment[seg].lines[z].y1 * sin (phi));
  y1neu = (segment[seg].lines[z].y1 * cos (phi) + segment[seg].lines[z].x1 * sin (phi));
  x2neu = (segment[seg].lines[z].x2 * cos (phi) - segment[seg].lines[z].y2 * sin (phi));
  y2neu = (segment[seg].lines[z].y2 * cos (phi) + segment[seg].lines[z].x2 * sin (phi));
  
  
  
  line (seg, x1neu, y1neu , x2neu, y2neu );
  }
  
  Tcl_Eval (MainInterp, buf);
  	
	
}

//*************************************************************************
//********** erzeugeGestalt
//*************************************************************************
void erzeugeGestalt ()
{
 SegNr = erzeugeSegment (6, 2);
 line (SegNr, -1, -1,  1, -1);
 line (SegNr, -1,  1,  1,  1);
 line (SegNr, -1, -1, -1,  1);
 line (SegNr,  1, -1,  1,  1);
 line (SegNr, -1,  0,  1.5,  0);

 SegNr = erzeugeSegment (9, 3);
 line (SegNr, -1, -1,  1, -1);
 line (SegNr, -1,  1,  1,  1);
 line (SegNr, -1, -1, -1,  1);
 line (SegNr,  1, -1,  1,  1);
 line (SegNr, -1, -1,  1,  1);
 line (SegNr, -1,  1,  1, -1);
 line (SegNr, -1,  0,  1.5,  0);

}


//===========================================================================



//*************************************************************************
//********** Init
//*************************************************************************
void initModell()
{
 erzeugeFenster (20, 15, "white");
 erzeugeGestalt();
}


//*************************************************************************
//********** Animate
//*************************************************************************
void animate ()
{
 for (int i = 1; i <= SegNr; i++){
  bewegeSegment (i, 4, 0);
  dreheSegment (i, 45);
 }
//  flush ();
}



//===========================================================================




int MainTclCmd (ClientData /*clientData*/, Tcl_Interp *interp,
                int /*argc*/, char *argv[] )
{
  MainInterp = interp;
  if ( !strcmp("Init", argv[1]) )
  {
     initModell();
  }
  else if ( !strcmp("Animate",  argv[1]) )
  {
     animate();
  }
  else if ( !strcmp("ExitTest", argv[1]) )
  {
    if (timerToken)
    {
      Tk_DeleteTimerHandler (timerToken);
      timerToken = NULL;
    }
  }
  return TCL_OK;
}
