Program Cub_Central;
uses
    CRT, Graph;
const
    Depth = 1000;      {Profunzime}

type
     TVector  = packed array[1..3] of Real;
     TReper   = packed array[0..3] of TVector;   {O, e1, e2, e3}

var
    GD, GM     : integer;  {Pentru initierea modului grafic}
    MidX, MidY : word;     {Mijlocul ecranului}
    R          : TReper;
{---------------------------------------------------------------}
procedure CoordAbsol(P: TVector; E: TReper; var M: TVector);
    {-----------------------------------------------------------}
    procedure AddVec(var r: TVector; v1, v2: TVector);
    begin  { r := v1 + v2 }
       r[1] := v1[1] + v2[1];
       r[2] := v1[2] + v2[2];
       r[3] := v1[3] + v2[3];
    end;
    {-----------------------------------------------------------}
    procedure MulScal(var r: TVector; v: TVector; scal: Real);
    begin  { r := v * scal }
       r[1] := v[1] * scal;
       r[2] := v[2] * scal;
       r[3] := v[3] * scal;
    end;
    {-----------------------------------------------------------}
begin { M = (O + P1*e1 + P2*e2 +P3*e3) }
   MulScal(e[1], e[1], P[1]); {e1 := P1 * e1}
   MulScal(e[2], e[2], P[2]); {e2 := P2 * e2}
   MulScal(e[3], e[3], P[3]); {e3 := P3 * e3}
   AddVec(M, e[0], e[1]);     {M := O + e1}
   AddVec(M, M,    e[2]);     {M := M + e2}
   AddVec(M, M,    e[3]);     {M := M + e3}
end;
{---------------------------------------------------------------}
procedure Proiec(xyz: TVector; var xy: TVector);
begin  {3D -> 2D}
  { Atentie! xyz[3] <> -Depth, altfel se obtine eroare }
  if (xyz[3] <> -Depth) then  xy[3] := Depth  / (xyz[3]+Depth)
                        else  xy[3] := 1.7e+38; {infinit}

  xy [1] := xyz[1] * xy[3]; { x := x * (Depth / (z+Depth)) }
  xy [2] := xyz[2] * xy[3]; { y := y * (Depth / (z+Depth)) }
end;
{---------------------------------------------------------------}
procedure Proiec_Central(P: TVector; E: TReper; var M: TVector);
begin
  CoordAbsol(P, E, P);
  Proiec(P, M);  
end;
{---------------------------------------------------------------}
function Line2d(p1, p2: TVector): boolean;
begin
   {??? punctele pot iesi in afara limitelor ecranului}
   Line( round(p1[1]) + MidX, -round(p1[2]) + MidY, 
         round(p2[1]) + MidX, -round(p2[2]) + MidY );
end;
{---------------------------------------------------------------}
procedure Cub(Sis: TReper; raz: integer);
var P :array[0..7] of TVector;
    i : integer;
begin
  {Amplasarea punctelor in spatiu (in reper)}
  for i:=0 to 7 do begin
     if (i and 1) <> 0 then p[i][1] := raz else p[i][1] := -raz;
     if (i and 2) <> 0 then p[i][2] := raz else p[i][2] := -raz;
     if (i and 4) <> 0 then p[i][3] := raz else p[i][3] := -raz;
  end;

  {Calcularea coordonatelor plane - I metoda}
  for i:=0 to 7 do  Proiec_Central(P[i], Sis, P[i]);

  {Desenarea segmentelor figurii}
  for i:=0 to 3 do begin
    Line2D(P[i],           P[i + 4]);
    Line2D(P[2*i],         P[2*i + 1]);
    Line2D(P[i+i and 2+2], P[i+i and 2]);
  end;
end;
{---------------------------------------------------------------}

BEGIN
   GD := Detect;
   InitGraph(GD, GM, '');
   if (GraphResult <> 0) then begin
      Writeln('Erroare initializare modul grafic!');
      readkey;
      Halt(1);
   end;
   MidX := GetMaxX div 2;
   MidY := GetMaxY div 2;

   {Pozitionarea si orientarea reperului in spatiu}
   R[0][1] :=  0;   R[0][2] := 0;   R[0][3] := 0; { O(0, 0, 0) }
   R[1][1] := 15;   R[1][2] := 0;   R[1][3] :=20; { e1(3,  0,  4) }
   R[2][1] :=  0;   R[2][2] :=25;   R[2][3] := 0; { e2(0,  5,  0) }
   R[3][1] :=-20;   R[3][2] := 0;   R[3][3] :=15; { e3(-4, 0,  3) }
   Cub(R, 5); {Deseneaza cubul in reperul R}
   readkey;

   ClearViewPort;
   {Pozitionarea si orientarea reperului in spatiu}
   R[0][1] :=   0;   R[0][2] :=  0;   R[0][3] :=   0; { O(0, 0, 0) }
   R[1][1] :=   9;   R[1][2] := 12;   R[1][3] :=  20; { e1(3,  0,  4) }
   R[2][1] := -12;   R[2][2] := 20;   R[2][3] :=   9; { e2(0,  5,  0) }
   R[3][1] :=  20;   R[3][2] :=  9;   R[3][3] := -12; { e3(-4, 0,  3) }
   Cub(R, 5); {Deseneaza cubul in reperul R}

   readkey;
   CloseGraph;
END.
