Task: Draw a rotating cube





Java: import java.awt.*;
import java.awt.event.ActionEvent;
import static java.lang.Math.*;
import javax.swing.*;

public class RotatingCube extends JPanel {
    double[][] nodes = {{-1, -1, -1}, {-1, -1, 1}, {-1, 1, -1}, {-1, 1, 1},
    {1, -1, -1}, {1, -1, 1}, {1, 1, -1}, {1, 1, 1}};

    int[][] edges = {{0, 1}, {1, 3}, {3, 2}, {2, 0}, {4, 5}, {5, 7}, {7, 6},
    {6, 4}, {0, 4}, {1, 5}, {2, 6}, {3, 7}};

    public RotatingCube() {
        setPreferredSize(new Dimension(640, 640));
        setBackground(Color.white);

        scale(100);
        rotateCube(PI / 4, atan(sqrt(2)));

        new Timer(17, (ActionEvent e) -> {
            rotateCube(PI / 180, 0);
            repaint();
        }).start();
    }

    final void scale(double s) {
        for (double[] node : nodes) {
            node[0] *= s;
            node[1] *= s;
            node[2] *= s;
        }
    }

    final void rotateCube(double angleX, double angleY) {
        double sinX = sin(angleX);
        double cosX = cos(angleX);

        double sinY = sin(angleY);
        double cosY = cos(angleY);

        for (double[] node : nodes) {
            double x = node[0];
            double y = node[1];
            double z = node[2];

            node[0] = x * cosX - z * sinX;
            node[2] = z * cosX + x * sinX;

            z = node[2];

            node[1] = y * cosY - z * sinY;
            node[2] = z * cosY + y * sinY;
        }
    }

    void drawCube(Graphics2D g) {
        g.translate(getWidth() / 2, getHeight() / 2);

        for (int[] edge : edges) {
            double[] xy1 = nodes[edge[0]];
            double[] xy2 = nodes[edge[1]];
            g.drawLine((int) round(xy1[0]), (int) round(xy1[1]),
                    (int) round(xy2[0]), (int) round(xy2[1]));
        }

        for (double[] node : nodes) 
            g.fillOval((int) round(node[0]) - 4, (int) round(node[1]) - 4, 8, 8);        
    }

    @Override
    public void paintComponent(Graphics gg) {
        super.paintComponent(gg);
        Graphics2D g = (Graphics2D) gg;
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);

        drawCube(g);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame f = new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setTitle("Rotating Cube");
            f.setResizable(false);
            f.add(new RotatingCube(), BorderLayout.CENTER);
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        });
    }
}







Ada: with Ada.Numerics.Elementary_Functions;

with SDL.Video.Windows.Makers;
with SDL.Video.Renderers.Makers;
with SDL.Events.Events;

procedure Rotating_Cube is

   Width  : constant := 500;
   Height : constant := 500;
   Offset : constant := 500.0 / 2.0;

   Window   : SDL.Video.Windows.Window;
   Renderer : SDL.Video.Renderers.Renderer;
   Event    : SDL.Events.Events.Events;
   Quit     : Boolean := False;

   type Node_Id   is new Natural;
   type Point_3D  is record X, Y, Z : Float;   end record;
   type Edge_Type is record A, B    : Node_Id; end record;

   Nodes : array (Node_Id range <>) of Point_3D :=
     ((-100.0, -100.0, -100.0), (-100.0, -100.0, 100.0), (-100.0, 100.0, -100.0),
      (-100.0, 100.0, 100.0),   (100.0, -100.0, -100.0), (100.0, -100.0, 100.0),
      (100.0, 100.0, -100.0),   (100.0, 100.0, 100.0));
   Edges : constant array (Positive range <>) of Edge_Type :=
     ((0, 1), (1, 3), (3, 2), (2, 0), (4, 5), (5, 7),
      (7, 6), (6, 4), (0, 4), (1, 5), (2, 6), (3, 7));

   use Ada.Numerics.Elementary_Functions;

   procedure Rotate_Cube (AngleX, AngleY : in Float) is
      SinX : constant Float := Sin (AngleX);
      CosX : constant Float := Cos (AngleX);
      SinY : constant Float := Sin (AngleY);
      CosY : constant Float := Cos (AngleY);
      X, Y, Z : Float;
   begin
      for Node of Nodes loop
         X := Node.X;
         Y := Node.Y;
         Z := Node.Z;
         Node.X := X * CosX - Z * SinX;
         Node.Z := Z * CosX + X * SinX;
         Z := Node.Z;
         Node.Y := Y * CosY - Z * SinY;
         Node.Z := Z * CosY + Y * SinY;
      end loop;
   end Rotate_Cube;

   function Poll_Quit return Boolean is
      use type SDL.Events.Event_Types;
   begin
      while SDL.Events.Events.Poll (Event) loop
         if Event.Common.Event_Type = SDL.Events.Quit then
            return True;
         end if;
      end loop;
      return False;
   end Poll_Quit;

   procedure Draw_Cube (Quit : out Boolean) is
      use SDL.C;
      Pi : constant := Ada.Numerics.Pi;
      Xy1, Xy2 : Point_3D;
   begin
      Rotate_Cube (Pi / 4.0, Arctan (Sqrt (2.0)));
      for Frame in 0 .. 359 loop
         Renderer.Set_Draw_Colour ((0, 0, 0, 255));
         Renderer.Fill (Rectangle => (0, 0, Width, Height));

         Renderer.Set_Draw_Colour ((0, 220, 0, 255));
         for Edge of Edges loop
            Xy1 := Nodes (Edge.A);
            Xy2 := Nodes (Edge.B);
            Renderer.Draw (Line => ((int (Xy1.X + Offset), int (Xy1.Y + Offset)),
                                    (int (Xy2.X + Offset), int (Xy2.Y + Offset))));
         end loop;
         Rotate_Cube (Pi / 180.0, 0.0);
         Window.Update_Surface;
         Quit := Poll_Quit;
         exit when Quit;
         delay 0.020;
      end loop;
   end Draw_Cube;

begin
   if not SDL.Initialise (Flags => SDL.Enable_Screen) then
      return;
   end if;

   SDL.Video.Windows.Makers.Create (Win      => Window,
                                    Title    => "Rotating cube",
                                    Position => SDL.Natural_Coordinates'(X => 10, Y => 10),
                                    Size     => SDL.Positive_Sizes'(Width, Height),
                                    Flags    => 0);
   SDL.Video.Renderers.Makers.Create (Renderer, Window.Get_Surface);

   while not Quit loop
      Draw_Cube (Quit);
   end loop;

   Window.Finalize;
   SDL.Finalise;
end Rotating_Cube;