Code Sketch


yadnesh shahare using gemini
By: Mhalsakant School
Category: Programming
// --- Kojo 3x3 Dynamic Color Cube (Rubik's Cube) ---
cleari()
setBackground(Color(15, 15, 25)) // ????? ??????????

// 3D ????????
case class Vector3D(x: Double, y: Double, z: Double)

val size = canvasBounds.width * 0.4
val viewAngleHalf = Math.toRadians(60.0 / 2.0)

// 3D ???????? (X, Y, Z ???????? ????????????)
def rotateX(p: Vector3D, angle: Double): Vector3D = {
  val rad = Math.toRadians(angle)
  Vector3D(p.x, p.y * Math.cos(rad) - p.z * Math.sin(rad), p.y * Math.sin(rad) + p.z * Math.cos(rad))
}

def rotateY(p: Vector3D, angle: Double): Vector3D = {
  val rad = Math.toRadians(angle)
  Vector3D(p.x * Math.cos(rad) + p.z * Math.sin(rad), p.y, -p.x * Math.sin(rad) + p.z * Math.cos(rad))
}

def rotateZ(p: Vector3D, angle: Double): Vector3D = {
  val rad = Math.toRadians(angle)
  Vector3D(p.x * Math.cos(rad) - p.y * Math.sin(rad), p.x * Math.sin(rad) + p.y * Math.cos(rad), p.z)
}

// 3D ?? 2D ????????? ??????????
def project(p: Vector3D): (Double, Double, Double) = {
  val distance = size + 350
  val pz = p.z + distance
  val factor = size / (pz * Math.tan(viewAngleHalf))
  (p.x * factor, p.y * factor, pz)
}

// ?? (Cube) ???? 6 ??????? ??? (Rubik's Standard Colors)
val faceColors = Map(
  "FRONT"  -> Color(255, 50, 50),   // ??? (Red)
  "BACK"   -> Color(255, 140, 0),   // ?????? (Orange)
  "TOP"    -> Color(255, 255, 255), // ?????? (White)
  "BOTTOM" -> Color(255, 215, 0),   // ????? (Yellow)
  "RIGHT"  -> Color(50, 205, 50),   // ????? (Green)
  "LEFT"   -> Color(30, 144, 255)   // ???? (Blue)
)

// ?? ???? Cube ?? ????
case class MiniCube(cx: Double, cy: Double, cz: Double, s: Double) {
  val h = s / 2.0
  
  // ?? ?? 8 ????? (Vertices)
  val vertices = Seq(
    Vector3D(cx - h, cy - h, cz - h), // 0
    Vector3D(cx + h, cy - h, cz - h), // 1
    Vector3D(cx + h, cy + h, cz - h), // 2
    Vector3D(cx - h, cy + h, cz - h), // 3
    Vector3D(cx - h, cy - h, cz + h), // 4
    Vector3D(cx + h, cy - h, cz + h), // 5
    Vector3D(cx + h, cy + h, cz + h), // 6
    Vector3D(cx - h, cy + h, cz + h)  // 7
  )

  // ? ???????? (Faces)
  val faces = Seq(
    ("FRONT",  Seq(4, 5, 6, 7), Vector3D(0, 0, 1)),
    ("BACK",   Seq(1, 0, 3, 2), Vector3D(0, 0, -1)),
    ("TOP",    Seq(3, 2, 6, 7), Vector3D(0, 1, 0)),
    ("BOTTOM", Seq(4, 5, 1, 0), Vector3D(0, -1, 0)),
    ("RIGHT",  Seq(5, 1, 2, 6), Vector3D(1, 0, 0)),
    ("LEFT",   Seq(0, 4, 7, 3), Vector3D(-1, 0, 0))
  )
}

// 3x3x3 ?? ?? ???? Cube ???? ????
val cubeSpacing = 34.0
val miniCubeScale = 30.0

val rubiksCube = for {
  x <- -1 to 1
  y <- -1 to 1
  z <- -1 to 1
} yield MiniCube(x * cubeSpacing, y * cubeSpacing, z * cubeSpacing, miniCubeScale)

// ??????? ??? (Animation Loop)
animateWithState(0.0) { angle =>
  erasePictures()

  // 3D ????? ?????? ?????
  val rotX = angle * 0.7
  val rotY = angle * 1.0
  val rotZ = angle * 0.3

  // ???? ???????? (Faces) ???? ???? Z-Depth ????? ????? ???? (Painter's Algorithm)
  var allRenderFaces = Seq.empty[(Seq[(Double, Double)], Color, Double)]

  rubiksCube.foreach { mini =>
    mini.faces.foreach { case (faceName, idxs, normal) =>
      
      // ???? ????? ?????? 3D ????????? ????
      val rotatedVerts = idxs.map { i =>
        val v = mini.vertices(i)
        val r = rotateZ(rotateY(rotateX(v, rotX), rotY), rotZ)
        project(r)
      }

      // Normal Vector ?? ???? ???? ???-??? ????? ????
      val rNormal = rotateZ(rotateY(rotateX(normal, rotX), rotY), rotZ)

      if (rNormal.z < 0) { // ???? ??????? ???????? ???? ???
        val points2D = rotatedVerts.map { case (px, py, _) => (px, py) }
        val avgZ = rotatedVerts.map(_._3).sum / 4.0
        val baseColor = faceColors(faceName)

        allRenderFaces = allRenderFaces :+ (points2D, baseColor, avgZ)
      }
    }
  }

  // ????? ???????? ??? ??? ????? ???? ????? (Depth Sorting)
  val sortedFaces = allRenderFaces.sortBy(_._3).reverse

  // ????????? ???? ????
  sortedFaces.foreach { case (pts, color, _) =>
    val facePic = Picture.fromVertexShape { p =>
      p.beginShape()
      pts.foreach { case (x, y) => p.vertex(x, y) }
      p.endShape()
    }
    facePic.setFillColor(color)
    facePic.setPenColor(Color(20, 20, 20)) // ???? ?????? (Plastic Frame Effect)
    facePic.setPenThickness(2)
    draw(facePic)
  }

  angle + 1.5
}