Task
Draw a rotating cube.

It should be oriented with one vertex pointing straight up, and its opposite vertex on the main diagonal (the one farthest away) straight down. It can be solid or wire-frame, and you can use ASCII art if your language doesn't have graphical capabilities. Perspective is optional.




Related tasks
 Draw a cuboid
 write language name in 3D ASCII


import java.awt.event.ActionEvent
import java.awt._
 
import javax.swing.{JFrame, JPanel, Timer}
 
import scala.math.{Pi, atan, cos, sin, sqrt}
 
object RotatingCube extends App {
 
  class RotatingCube extends JPanel {
    private val vertices: Vector[Array[Double]] =
      Vector(Array(-1, -1, -1), Array(-1, -1, 1), Array(-1, 1, -1),
        Array(-1, 1, 1), Array(1, -1, -1), Array(1, -1, 1), Array(1, 1, -1), Array(1, 1, 1))
 
    private val edges: Vector[(Int, Int)] =
      Vector((0, 1), (1, 3), (3, 2), (2, 0), (4, 5), (5, 7),
        (7, 6), (6, 4), (0, 4), (1, 5), (2, 6), (3, 7))
 
    setPreferredSize(new Dimension(640, 640))
    setBackground(Color.white)
    scale(100)
    rotateCube(Pi / 4, atan(sqrt(2)))
 
    new Timer(17, (_: ActionEvent) => {
      rotateCube(Pi / 180, 0)
      repaint()
    }).start()
 
    override def paintComponent(gg: Graphics): Unit = {
      def drawCube(g: Graphics2D): Unit = {
        g.translate(getWidth / 2, getHeight / 2)
        for {edge <- edges
             xy1: Array[Double] = vertices(edge._1)
             xy2: Array[Double] = vertices(edge._2)
             } {
          g.drawLine(xy1(0).toInt, xy1(1).toInt, xy2(0).toInt, xy2(1).toInt)
          g.fillOval(xy1(0).toInt -4, xy1(1).toInt - 4, 8, 8)
          g.setColor(Color.black)
        }
      }
 
      super.paintComponent(gg)
      val g: Graphics2D = gg.asInstanceOf[Graphics2D]
      g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
      drawCube(g)
    }
 
    private def scale(s: Double): Unit = {
      for {node <- vertices
           i <- node.indices
           } node(i) *= s
    }
 
    private def rotateCube(angleX: Double, angleY: Double): Unit = {
      def sinCos(x: Double) = (sin(x), cos(x))
 
      val ((sinX, cosX), (sinY, cosY)) = (sinCos(angleX), sinCos(angleY))
 
      for {
        node <- vertices
        x: Double = node(0)
        y: Double = node(1)
      } {
        def f(p: Double, q: Double)(a: Double, b: Double) = a * p + b * q
 
        def fx(a: Double, b: Double) = f(cosX, sinX)(a, b)
 
        def fy(a: Double, b: Double) = f(cosY, sinY)(a, b)
 
        node(0) = fx(x, -node(2))
        val z = fx(node(2), x)
        node(1) = fy(y, -z)
        node(2) = fy(z, y)
      }
    }
 
  }
 
  new JFrame("Rotating Cube") {
    add(new RotatingCube(), BorderLayout.CENTER)
    pack()
    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE)
    setLocationRelativeTo(null)
    setResizable(false)
    setVisible(true)
  }
 
}