#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>

#include "comdef.H"

extern Display *disp;
extern GC gc;       
extern Window window;
extern int fg, bg;  
extern unsigned long pixels[256];
extern GC gc, pmgc; 
extern Pixmap pixmap;
extern unsigned long event_mask;

extern struct TSystem System;
extern int DrwX, DrwY, PrevX, PrevY;
extern double DX, DY, DZ, RX, RY, ax, ay, az, dx, dy, dz;
extern unsigned int WMaxX, WMaxY;
extern int DrwX, DrwY, PrevX, PrevY;
extern int iax, iay, iaz, piax, piay, piaz, playpressed, track, mode;
extern int scheme, ConfigMode, prevmode, prevplay;
extern int mass, radius, space, collision, zoom, zoommode;
extern double DimFact;
extern int i, j;

extern int TrX(double px, double py, double pz);
extern int TrY(double px, double py, double pz);
extern int TrX_2D(double x);
extern int TrY_2D(double x);
extern DrawCircle(int x, int y, int rad);

double MGAcc, QDist, Dist, NewAngle, MVel; 


double sqr(double x)
{
  return x*x;
}

double Angle(double x, double y)
{
  return (x<0 ?  PI+atan(y/x) : (x>0 ? atan(y/x) : PI/2));
}

ProfDrawSystem_2D()
{
  long i, j;

  for(i=0; i<System.nObjects; i++) 
    if (!System.Locked[i]) {
      for(j=0; j<System.nObjects; j++) {
        if (i!=j) {
          DX=System.X[j]-System.X[i];
          DY=System.Y[j]-System.Y[i];
          MGAcc=System.Mass[j]*System.G*System.dt/(QDist=sqr(DX)+sqr(DY));
          Dist=sqrt(QDist);
          if ((System.collision==2)||
              (QDist>sqr(System.Radius[j]+System.Radius[i])))
          {
            if (MGAcc>System.MaxAcc) MGAcc=System.MaxAcc;
            System.VelX[i]+=MGAcc*DX/Dist;
            System.VelY[i]+=MGAcc*DY/Dist;
          } else {
            NewAngle=2*Angle(DX, DY)-Angle(System.VelX[i],
                   System.VelY[i])+PI;
            MVel=sqrt(sqr(System.VelX[i])+
                      sqr(System.VelY[i]));
            System.VelX[i]=MVel*cos(NewAngle);
            System.VelY[i]=MVel*sin(NewAngle);
            MGAcc=0;
          }
        }
        System.X[i]+=System.VelX[i]*System.dt+MGAcc*DX/Dist*sqr(System.dt)/2;
        System.Y[i]+=System.VelY[i]*System.dt+MGAcc*DY/Dist*sqr(System.dt)/2;
        if (System.space==1) {
          if (System.X[i]>System.XMax)
            System.X[i]-=System.XMax-System.XMin;
          else
            if (System.X[i]<System.XMin)
              System.X[i]+=System.XMax-System.XMin;
          if (System.Y[i]>System.YMax)
            System.Y[i]-=System.YMax-System.YMin;
          else
            if (System.Y[i]<System.YMin)
              System.Y[i]+=System.YMax-System.YMin;
        }
        DrwX=TrX_2D(System.X[i]);
        DrwY=TrY_2D(System.Y[i]);
        if (System.track==1) {
          if ((PrevX!=DrwX)||(PrevY!=DrwY)) {
            XSetForeground(disp, gc, bg);
            DrawCircle(PrevX, PrevY, (int)floor(WMaxX>WMaxY ?
            System.Radius[i]/(System.YMax-System.YMin)*WMaxY :
            System.Radius[i]/(System.XMax-System.XMin)*WMaxX));
            XSetForeground(disp, gc, pixels[1+i]);
            DrawCircle(PrevX=DrwX, PrevY=DrwY, (int)floor(WMaxX>WMaxY ?
            System.Radius[i]/(System.YMax-System.YMin)*WMaxY :
            System.Radius[i]/(System.XMax-System.XMin)*WMaxX));
            PrevX=DrwX;
	    PrevY=DrwY;            
          }
        } else
          if (System.track==3) {
            XSetForeground(disp, gc, pixels[1+i]);
            XDrawPoint(disp, window, gc, DrwX, DrwY);
          } else {
            XSetForeground(disp, gc, pixels[10+
             (int)floor(System.Col_Amp/10*sqrt(sqr(System.VelX[i])+
              sqr(System.VelY[i])))%NCOLORS]);
            XDrawPoint(disp, window, gc, DrwX, DrwY);
          }
      }
    }
}

SuckDrawSystem_2D()
{
  for(i=0; i<System.nObjects; i++) 
    if (!System.Locked[i]) {
      for(j=0; j<System.nObjects; j++) {
        if (i!=j) {
          DX=System.X[j]-System.X[i];
          DY=System.Y[j]-System.Y[i];
          MGAcc=System.Mass[j]*System.G*System.dt/(QDist=sqr(DX)+sqr(DY));
          Dist=sqrt(QDist);
          if ((System.collision==2)||
              (QDist>sqr(System.Radius[j]+System.Radius[i])))
          {
            if (MGAcc>System.MaxAcc) MGAcc=System.MaxAcc;
            System.VelX[i]+=MGAcc*DX/Dist;
            System.VelY[i]+=MGAcc*DY/Dist;
          } else {
            NewAngle=2*Angle(DX, DY)-Angle(System.VelX[i],
                   System.VelY[i])+PI;
            MVel=sqrt(sqr(System.VelX[i])+
                      sqr(System.VelY[i]));
            System.VelX[i]=MVel*cos(NewAngle);
            System.VelY[i]=MVel*sin(NewAngle);
          }
        }
        System.X[i]+=System.VelX[i]*System.dt;
        System.Y[i]+=System.VelY[i]*System.dt;
        if (System.space==1) {
          if (System.X[i]>System.XMax)
            System.X[i]-=System.XMax-System.XMin;
          else
            if (System.X[i]<System.XMin)
              System.X[i]+=System.XMax-System.XMin;
          if (System.Y[i]>System.YMax)
            System.Y[i]-=System.YMax-System.YMin;
          else
            if (System.Y[i]<System.YMin)
              System.Y[i]+=System.YMax-System.YMin;
        }
        DrwX=TrX_2D(System.X[i]);
        DrwY=TrY_2D(System.Y[i]);
        if (System.track==1) {
          if ((PrevX!=DrwX)||(PrevY!=DrwY)) {
            XSetForeground(disp, gc, bg);
            DrawCircle(PrevX, PrevY, (int)floor(WMaxX>WMaxY ?
            System.Radius[i]/(System.YMax-System.YMin)*WMaxY :
            System.Radius[i]/(System.XMax-System.XMin)*WMaxX));
            XSetForeground(disp, gc, pixels[1+i]);
            DrawCircle(PrevX=DrwX, PrevY=DrwY, (int)floor(WMaxX>WMaxY ?
            System.Radius[i]/(System.YMax-System.YMin)*WMaxY :
            System.Radius[i]/(System.XMax-System.XMin)*WMaxX));
            PrevX=DrwX;
	    PrevY=DrwY;
          }
        } else
          if (System.track==3) {
            XSetForeground(disp, gc, pixels[1+i]);
            XDrawPoint(disp, window, gc, DrwX, DrwY);
          } else {
            XSetForeground(disp, gc, pixels[10+
             (int)floor(System.Col_Amp/10*sqrt(sqr(System.VelX[i])+
              sqr(System.VelY[i])))%NCOLORS]);
            XDrawPoint(disp, window, gc, DrwX, DrwY);
          }
      }
    }
}

ArtDrawSystem_2D()
{
  long i, j;

  for(i=0; i<System.nObjects; i++) 
    if (!System.Locked[i]) {
      for(j=0; j<System.nObjects; j++) {
        if (i!=j) {
          DX=System.X[j]-System.X[i];
          DY=System.Y[j]-System.Y[i];
          MGAcc=System.Mass[j]*System.G*System.dt/(QDist=sqr(DX)+sqr(DY));
          Dist=sqrt(QDist);
          if ((System.collision==2)||
              (QDist>sqr(System.Radius[j]+System.Radius[i])))
          {
            if (MGAcc>System.MaxAcc) MGAcc=System.MaxAcc;
            System.VelX[i]+=MGAcc*DX/Dist;
            System.VelY[i]+=MGAcc*DY/Dist;
          } else {
            NewAngle=2*Angle(DX, DY)-Angle(System.VelX[i],
                   System.VelY[i])+PI;
            MVel=sqrt(sqr(System.VelX[i])+
                      sqr(System.VelY[i]));
            System.VelX[i]=MVel*cos(NewAngle);
            System.VelY[i]=MVel*sin(NewAngle);
            MGAcc=0;
          }
        }

        System.X[i]=System.X[i]/2+System.VelX[i]*System.dt+
            sqrt((QDist>System.G ? 0 : QDist))*DX/Dist;
        System.Y[i]=System.Y[i]/2+System.VelY[i]*System.dt+
                    sqrt((QDist>System.G ? 0 : QDist))*DY/Dist;
        if (System.space==1) {
          if (System.X[i]>System.XMax)
            System.X[i]-=System.XMax-System.XMin;
          else
            if (System.X[i]<System.XMin)
              System.X[i]+=System.XMax-System.XMin;
          if (System.Y[i]>System.YMax)
            System.Y[i]-=System.YMax-System.YMin;
          else
            if (System.Y[i]<System.YMin)
              System.Y[i]+=System.YMax-System.YMin;
        }
        DrwX=TrX_2D(System.X[i]);
        DrwY=TrY_2D(System.Y[i]);
        if (System.track==1) {
          if ((PrevX!=DrwX)||(PrevY!=DrwY)) {
            XSetForeground(disp, gc, bg);
            DrawCircle(PrevX, PrevY, (int)floor(WMaxX>WMaxY ?
            System.Radius[i]/(System.YMax-System.YMin)*WMaxY :
            System.Radius[i]/(System.XMax-System.XMin)*WMaxX));
            XSetForeground(disp, gc, pixels[1+i]);
            DrawCircle(PrevX=DrwX, PrevY=DrwY, (int)floor(WMaxX>WMaxY ?
            System.Radius[i]/(System.YMax-System.YMin)*WMaxY :
            System.Radius[i]/(System.XMax-System.XMin)*WMaxX));
            PrevX=DrwX;
	    PrevY=DrwY;
          }
        } else
          if (System.track==3) {
            XSetForeground(disp, gc, pixels[1+i]);
            XDrawPoint(disp, window, gc, DrwX, DrwY);
          } else {
            XSetForeground(disp, gc, pixels[10+
             (int)floor(System.Col_Amp/10*sqrt(sqr(System.VelX[i])+
              sqr(System.VelY[i])))%NCOLORS]);
            XDrawPoint(disp, window, gc, DrwX, DrwY);
          }
      }
    }
} 

ProfDrawSystem_3D()
{
  long i, j;

  for(i=0; i<System.nObjects; i++) 
    if (!System.Locked[i]) {
      for(j=0; j<System.nObjects; j++) {
        if (i!=j) {
          DX=System.X[j]-System.X[i];
          DY=System.Y[j]-System.Y[i];
          DZ=System.Z[j]-System.Z[i];
          MGAcc=System.Mass[j]*System.G*System.dt/(QDist=sqr(DX)+sqr(DY)+sqr(DZ));
          Dist=sqrt(QDist);
            if (MGAcc>System.MaxAcc) MGAcc=System.MaxAcc;
            System.VelX[i]+=MGAcc*DX/Dist;
            System.VelY[i]+=MGAcc*DY/Dist;
            System.VelZ[i]+=MGAcc*DZ/Dist;
        }
        System.X[i]+=System.VelX[i]*System.dt+MGAcc*DX/Dist*sqr(System.dt)/2;;
        System.Y[i]+=System.VelY[i]*System.dt+MGAcc*DY/Dist*sqr(System.dt)/2;;
        System.Z[i]+=System.VelZ[i]*System.dt+MGAcc*DZ/Dist*sqr(System.dt)/2;;
        if (System.space==1) {
          if (System.X[i]>System.XMax)
            System.X[i]-=System.XMax-System.XMin;
          else
            if (System.X[i]<System.XMin)
              System.X[i]+=System.XMax-System.XMin;
          if (System.Y[i]>System.YMax)
            System.Y[i]-=System.YMax-System.YMin;
          else
            if (System.Y[i]<System.YMin)
              System.Y[i]+=System.YMax-System.YMin;
          if (System.Z[i]>System.ZMax)
            System.Z[i]-=System.ZMax-System.ZMin;
          else
            if (System.Z[i]<System.ZMin)
              System.Z[i]+=System.ZMax-System.ZMin;
        }
        if (System.track==1) {
          DrwX=TrX(System.X[i], System.Y[i], System.Z[i]);
          DrwY=TrY(System.X[i], System.Y[i], System.Z[i]);
          if ((PrevX!=DrwX)||(PrevY!=DrwY)) {
            XSetForeground(disp, gc, bg);
            DrawCircle(PrevX, PrevY,
            (int)floor(WMaxX>WMaxY ?
            System.Radius[i]/(System.YMax-System.YMin)*WMaxY :   
            System.Radius[i]/(System.XMax-System.XMin)*WMaxX));  
            XSetForeground(disp, gc, pixels[1+i]);
            DrawCircle(PrevX=DrwX, PrevY=DrwY,                           
            (int)floor(WMaxX>WMaxY ?
            System.Radius[i]/(System.YMax-System.YMin)*WMaxY :   
            System.Radius[i]/(System.XMax-System.XMin)*WMaxX)); 
            PrevX=DrwX;
	    PrevY=DrwY; 
          }
        } else
          if (System.track==3) {
            XSetForeground(disp, gc, pixels[1+i]);
            XDrawPoint(disp, window, gc,
             TrX(System.X[i], System.Y[i], System.Z[i]),
             TrY(System.X[i], System.Y[i], System.Z[i]));
          } else {
            XSetForeground(disp, gc, pixels[10+
             ((int)floor(System.Col_Amp/10*sqrt(sqr(System.VelX[i])+
             sqr(System.VelY[i])+sqr(System.VelZ[i]))))%
                 NCOLORS]);
            XDrawPoint(disp, window, gc,
             TrX(System.X[i], System.Y[i], System.Z[i]),
             TrY(System.X[i], System.Y[i], System.Z[i]));
          }
      }
    }
}

SuckDrawSystem_3D()
{
  long i, j;

  for(i=0; i<System.nObjects; i++) 
    if (!System.Locked[i]) {
      for(j=0; j<System.nObjects; j++) {
        if (i!=j) {
          DX=System.X[j]-System.X[i];
          DY=System.Y[j]-System.Y[i];
          DZ=System.Z[j]-System.Z[i];
          MGAcc=System.Mass[j]*System.G*System.dt/(QDist=sqr(DX)+sqr(DY)+sqr(DZ));
          Dist=sqrt(QDist);
            if (MGAcc>System.MaxAcc) MGAcc=System.MaxAcc;
            System.VelX[i]+=MGAcc*DX/Dist;
            System.VelY[i]+=MGAcc*DY/Dist;
            System.VelZ[i]+=MGAcc*DZ/Dist;
        }
        System.X[i]+=System.VelX[i]*System.dt;
        System.Y[i]+=System.VelY[i]*System.dt;
        System.Z[i]+=System.VelZ[i]*System.dt;
        if (System.space==1) {
          if (System.X[i]>System.XMax)
            System.X[i]-=System.XMax-System.XMin;
          else
            if (System.X[i]<System.XMin)
              System.X[i]+=System.XMax-System.XMin;
          if (System.Y[i]>System.YMax)
            System.Y[i]-=System.YMax-System.YMin;
          else
            if (System.Y[i]<System.YMin)
              System.Y[i]+=System.YMax-System.YMin;
          if (System.Z[i]>System.ZMax)
            System.Z[i]-=System.ZMax-System.ZMin;
          else
            if (System.Z[i]<System.ZMin)
              System.Z[i]+=System.ZMax-System.ZMin;
        }
        if (System.track==1) {
          DrwX=TrX(System.X[i], System.Y[i], System.Z[i]);
          DrwY=TrY(System.X[i], System.Y[i], System.Z[i]);
          if ((PrevX!=DrwX)||(PrevY!=DrwY)) {
            XSetForeground(disp, gc, bg);
            DrawCircle(PrevX, PrevY,
            (int)floor(WMaxX>WMaxY ?
            System.Radius[i]/(System.YMax-System.YMin)*WMaxY :   
            System.Radius[i]/(System.XMax-System.XMin)*WMaxX));  
            XSetForeground(disp, gc, pixels[1+i]);
            DrawCircle(PrevX=DrwX, PrevY=DrwY,                           
            (int)floor(WMaxX>WMaxY ?
            System.Radius[i]/(System.YMax-System.YMin)*WMaxY :   
            System.Radius[i]/(System.XMax-System.XMin)*WMaxX)); 
            PrevX=DrwX;
	    PrevY=DrwY; 
          }
        } else
          if (System.track==3) {
            XSetForeground(disp, gc, pixels[1+i]);
            XDrawPoint(disp, window, gc,
             TrX(System.X[i], System.Y[i], System.Z[i]),
             TrY(System.X[i], System.Y[i], System.Z[i]));
          } else {
            XSetForeground(disp, gc, pixels[10+
             ((int)floor(System.Col_Amp/10*sqrt(sqr(System.VelX[i])+
             sqr(System.VelY[i])+sqr(System.VelZ[i]))))%
                 NCOLORS]);
            XDrawPoint(disp, window, gc,
             TrX(System.X[i], System.Y[i], System.Z[i]),
             TrY(System.X[i], System.Y[i], System.Z[i]));
          }
      }
    }
}

ArtDrawSystem_3D()
{
  long i, j;

  for(i=0; i<System.nObjects; i++) 
    if (!System.Locked[i]) {
      for(j=0; j<System.nObjects; j++) {
        if (i!=j) {
          DX=System.X[j]-System.X[i];
          DY=System.Y[j]-System.Y[i];
          DZ=System.Z[j]-System.Z[i];
          MGAcc=System.Mass[j]*System.G*System.dt/(QDist=sqr(DX)+sqr(DY)+sqr(DZ));
          Dist=sqrt(QDist);
            if (MGAcc>System.MaxAcc) MGAcc=System.MaxAcc;
            System.VelX[i]+=MGAcc*DX/Dist;
            System.VelY[i]+=MGAcc*DY/Dist;
            System.VelZ[i]+=MGAcc*DZ/Dist;
        }
        System.X[i]=System.X[i]/2+System.VelX[i]*System.dt+
            sqrt((QDist>System.G ? 0 : QDist))*DX/Dist;
        System.Y[i]=System.Y[i]/2+System.VelY[i]*System.dt+
            sqrt((QDist>System.G ? 0 : QDist))*DY/Dist;
        System.Z[i]=System.Z[i]/2+System.VelZ[i]*System.dt+
            sqrt((QDist>System.G ? 0 : QDist))*DZ/Dist;
        if (System.space==1) {
          if (System.X[i]>System.XMax)
            System.X[i]-=System.XMax-System.XMin;
          else
            if (System.X[i]<System.XMin)
              System.X[i]+=System.XMax-System.XMin;
          if (System.Y[i]>System.YMax)
            System.Y[i]-=System.YMax-System.YMin;
          else
            if (System.Y[i]<System.YMin)
              System.Y[i]+=System.YMax-System.YMin;
          if (System.Z[i]>System.ZMax)
            System.Z[i]-=System.ZMax-System.ZMin;
          else
            if (System.Z[i]<System.ZMin)
              System.Z[i]+=System.ZMax-System.ZMin;
        }
        if (System.track==1) {
          DrwX=TrX(System.X[i], System.Y[i], System.Z[i]);
          DrwY=TrY(System.X[i], System.Y[i], System.Z[i]);
          if ((PrevX!=DrwX)||(PrevY!=DrwY)) {
            XSetForeground(disp, gc, bg);
            DrawCircle(PrevX, PrevY,
            (int)floor(WMaxX>WMaxY ?
            System.Radius[i]/(System.YMax-System.YMin)*WMaxY :   
            System.Radius[i]/(System.XMax-System.XMin)*WMaxX));  
            XSetForeground(disp, gc, pixels[1+i]);
            DrawCircle(PrevX=DrwX, PrevY=DrwY,                           
            (int)floor(WMaxX>WMaxY ?
            System.Radius[i]/(System.YMax-System.YMin)*WMaxY :   
            System.Radius[i]/(System.XMax-System.XMin)*WMaxX));  
            PrevX=DrwX;
	    PrevY=DrwY;
          }
        } else
          if (System.track==3) {
            XSetForeground(disp, gc, pixels[1+i]);
            XDrawPoint(disp, window, gc,
             TrX(System.X[i], System.Y[i], System.Z[i]),
             TrY(System.X[i], System.Y[i], System.Z[i]));
          } else {
            XSetForeground(disp, gc, pixels[10+
             ((int)floor(System.Col_Amp/10*sqrt(sqr(System.VelX[i])+
             sqr(System.VelY[i])+sqr(System.VelZ[i]))))%
                 NCOLORS]);
            XDrawPoint(disp, window, gc,
             TrX(System.X[i], System.Y[i], System.Z[i]),
             TrY(System.X[i], System.Y[i], System.Z[i]));
          }
      }
    }
}
