program Analisi2;
{$N+}
uses crt, graph, objects, drivers;

type Vector = array [1..3] of double;

const Points1 : array [1..8] of vector=
  ((4,-4,4),
   (4,4,4),
   (-4,-4,4),
   (-4,4,4),  {}
   (4,-4,-4),
   (4,4,-4),
   (-4,-4,-4),
   (-4,4,-4));

   C_Cartesian = 1;
   C_Spheric = 2;

type
  TAnalisi2 = object (TObject)
  constructor Init;
  procedure Run; virtual;
  destructor Done; virtual;
end;

type TScreen = object (TObject)
       Null : TPoint;
       Scale : integer;
end;

var Graphic : TScreen;
    Coord : byte;

procedure PointToPixel (U: Vector; var News : TPoint);
begin
  with graphic do
  begin
    News.X := Round (Graphic.Null.X + U [1] * cos (Pi/6)*Scale - U [2] * cos (Pi/6)*Scale);
    News.Y := Round (Graphic.Null.Y + U [1] * sin (Pi/6)*scale + U [2] * sin (Pi/6)*Scale - U [3] * Scale);
  end;
end;

procedure SphericToCartesian (x, y, z: double; var a, b, c : double);
begin
  a := x*sin(y)*sin(z);
  b := x*sin(y)*cos(z);
  c := x*cos(y);
end;

procedure DrawPoint (X, Y, Z : double);
var Final : TPoint;
    a, b, c : double;
    U : Vector;
begin
  case coord of
  C_Cartesian : begin
                  U [1] := X;
                  U [2] := Y;
                  U [3] := Z;
                  PointToPixel (U, Final);
                end;
  C_Spheric   : begin
                  SphericToCartesian (x,y,z,a,b,c);
                  U [1] := a;
                  U [2] := b;
                  U [3] := c;

                  PointToPixel (u, Final);
                end;
  end;
  PutPixel (Final.X, Final.Y, White);
  MoveTo (Final.X, Final.Y);
end;

{Dibuja un punto dado en forma de vector}
procedure DrawVPoint (U:Vector);
var Final : TPoint;
begin
  case Coord of
  C_Cartesian : begin
                  PointToPixel (U, Final);
                end;
  C_Spheric :   begin
                  SphericToCartesian (U[1],U[2],U[3],U[1],U[2],U[3]);
                end;
    end;
    PutPixel (Final.X, Final.Y, White);
    MoveTo (Final.X, Final.Y);

end;

procedure DrawLineTo (x1, y1, z1 : double);
var Final1 : TPoint;
    a, b, c : double;
    U : Vector;
begin
  case Coord of
    c_Cartesian :
      begin
        U [1] := X1;
        U [2] := Y1;
        U [3] := Z1;
        PointToPixel (U, Final1);
      end;
    c_Spheric :
      begin
        SphericToCartesian (x1, y1, z1, a, b, c);
        U [1] := a;
        U [2] := b;
        U [3] := c;

        PointToPixel (U, Final1);
      end;
  end;
  LineTo (Final1.X, Final1.Y);
end;

{T¡pico comando lineTo si las coordenadas se dan en forma vectorial}
procedure DrawVLineTo (U:Vector);
var Final : TPoint;
begin
  case Coord of
  C_Cartesian : begin
                  PointToPixel (U, Final);
                end;
  C_Spheric :   begin
                  SphericToCartesian (U[1],U[2],U[3],U[1],U[2],U[3]);
                end;
    end;
    LineTo (Final.X, Final.Y);

end;

procedure DrawLine (x1, y1, z1, x2, y2, z2 : double);
var Final1,
    Final2  : TPoint;
begin
  DrawPoint (x1, y1, z1);
  DrawLineTo (x2,y2, z2);
end;


function HCircle (r, x, y , z: double) : boolean;
var num1 : integer;
begin
  Drawpoint (-r+x, 0, z);
  for num1 := - round (r*100) to round (r*100) do
    if sqr(r)-sqr(num1/100) >= 0 then
        DrawLineTo (x+num1/100, y+sqrt (sqr (r)-sqr(num1/100)), z);
  Drawpoint (-r+x, 0, z);
  for num1 := - round (r*100) to round (r*100) do
    if sqr(r)-sqr(num1/100) >= 0 then
        DrawLineTo (x+num1/100, y-sqrt (sqr (r)-sqr(num1/100)), z);
end;

{Rota Alpha grados un vector U(X Y Z) alrededor del eje x y guarda el resultado
de la rotaci¢n en el vector V}
procedure RotateX (U : Vector; Alpha : double; var V : Vector);
begin
  Alpha := Alpha*pi/180;
  V[1] := cos (Alpha)*U[1] + sin (Alpha)*U[2];
  V[2] := -sin (Alpha)*U[1]+ cos (Alpha)*U[2];
  V[3] := U[3];
end;

procedure RotateY (U : Vector; Alpha : double; var V : Vector);
begin
  Alpha := Alpha*pi/180;
  V[1] := cos (Alpha)*U[1]+sin(Alpha)*U[3];
  V[2] := U[2];
  V[3] := -sin (Alpha)*U[1] + cos(Alpha)*U[3];
end;

procedure RotateZ (U : Vector; Alpha : double; var V : Vector);
begin
  Alpha := Alpha*pi/180;
  V[1] := U[1];
  V[2] := cos (Alpha)*U[2] + sin(Alpha)*U[3];
  V[3] := -sin (Alpha)*U[2]+cos (Alpha)*U[3];
end;

{Gira U Alpha grados alrededor del eje x, Beta alr. del y y Gamma alr. de
Z. Guarda el nuevo vector rotado en V}
procedure Rotate (U: Vector; var V: Vector; Alpha, Beta, Gamma : double);
begin
  RotateX (U, Alpha, V);
  RotateY (V, Beta, V);
  RotateZ (V, Gamma, V);
end;

{Rota un conjunto de vectores (Family) seg£n el criterio del procedimiento
anterior, guarda los nuevos valores en Dest}
procedure RotateVectors (Family: array of Vector; var Dest : array of Vector;
  Alpha, Beta, Gamma: double);
var Count : integer;
begin
 if High (Dest)= High (Family) then
  for Count := 0 to High (Family) do
    begin
      Rotate (Family [Count], Dest [Count], Alpha, Beta, Gamma);
    end;
end;

{TAnalisi2}
constructor TAnalisi2.Init;
var gd, gm : integer; {Variables gr ficas}
begin
  Coord := C_Cartesian;

  gd := Detect;
  InitGraph (gd, gm, 'c:\tp\bgi');

  {Inicializaci¢n de variables}
  Graphic.Null.X := Round (GetMaxX/2);
  Graphic.Null.Y := Round (GetMaxY/2);
  Graphic.Scale := 20;

  for gm := 1 to 8 do
    for gd:= 1 to 3 do

end;

procedure TAnalisi2.Run;
VAR NUM1, NUM2: INTEGER;
var v : array [1..8] of Vector; {cubo}
    c : char;
begin
{Asignar al vector v los valores de point}

  for num1 := 1 to 8 do
   for num2 := 1 to 3 do
     v [num1, num2] := points1 [num1, num2];

repeat

  ClearDevice;

  DrawLine (v[1,1],v[1,2],v[1,3],v[2,1],v[2,2],v[2,3]);
  DrawLine (v[3,1],v[3,2],v[3,3],v[4,1],v[4,2],v[4,3]);
  DrawLine (v[5,1],v[5,2],v[5,3],v[6,1],v[6,2],v[6,3]);
  DrawLine (v[7,1],v[7,2],v[7,3],v[8,1],v[8,2],v[8,3]);

  DrawLine (v[1,1],v[1,2],v[1,3],v[3,1],v[3,2],v[3,3]);
  DrawLine (v[2,1],v[2,2],v[2,3],v[4,1],v[4,2],v[4,3]);
  DrawLine (v[5,1],v[5,2],v[5,3],v[7,1],v[7,2],v[7,3]);
  DrawLine (v[6,1],v[6,2],v[6,3],v[8,1],v[8,2],v[8,3]);

  DrawLine (v[1,1],v[1,2],v[1,3],v[5,1],v[5,2],v[5,3]);
  DrawLine (v[2,1],v[2,2],v[2,3],v[6,1],v[6,2],v[6,3]);
  DrawLine (v[3,1],v[3,2],v[3,3],v[7,1],v[7,2],v[7,3]);
  DrawLine (v[4,1],v[4,2],v[4,3],v[8,1],v[8,2],v[8,3]);


  c := readkey;
  if c = #0 then c := readkey;
  case c of
         '4' : RotateVectors (v, v, -5, 0, 0);
    {->} '6' : RotateVectors (v, v, 5, 0, 0);
         '8' : RotateVectors (v, v, 0, 5, 0);
         '5' : RotateVectors (v, v, 0, -5, 0);
         '1' : RotateVectors (v, v, 0, 0, 5);
         '3' : RotateVectors (v, v, 0, 0, -5);

  end; {case}
  until c = #27;
end;

destructor TAnalisi2.Done;
begin
  CloseGraph;
end;

var Program1 : TAnalisi2;

begin
  Program1.Init;
  Program1.Run;
  Program1.Done;
end.