Code Sketch


yadnesh shahre
By: Mhalsakant School
Category: Art
cleari()

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

// Viewport and Geometry Configurations
val viewAngleHalf = Math.toRadians(90.0 / 2.0)
val size = canvasBounds.width * 0.5

// Cube / Body Faces Definition
val bottomFace = Seq(
  Vector3D(-100, -100, size),
  Vector3D(100, -100, size),
  Vector3D(100, -100, size + 200),
  Vector3D(-100, -100, size + 200),
  Vector3D(-100, -100, size)
)

val topFace = Seq(
  Vector3D(-100, 100, size),
  Vector3D(100, 100, size),
  Vector3D(100, 100, size + 200),
  Vector3D(-100, 100, size + 200),
  Vector3D(-100, 100, size)
) 

val frontFace = Seq(
  Vector3D(-100, -100, size),
  Vector3D(100, -100, size),
  Vector3D(100, 100, size),
  Vector3D(-100, 100, size),
  Vector3D(-100, -100, size)
)

val backFace = Seq(
  Vector3D(-100, -100, size + 200),
  Vector3D(100, -100, size + 200),
  Vector3D(100, 100, size + 200),
  Vector3D(-100, 100, size + 200),
  Vector3D(-100, -100, size + 200)
)

val leftFace = Seq(
  Vector3D(-100, -100, size),
  Vector3D(-100, -100, size + 200),
  Vector3D(-100, 100, size + 200),
  Vector3D(-100, 100, size),
  Vector3D(-100, -100, size)
)

val rightFace = Seq(
  Vector3D(100, -100, size),
  Vector3D(100, -100, size + 200),
  Vector3D(100, 100, size + 200),
  Vector3D(100, 100, size),
  Vector3D(100, -100, size)
)

val cube = Seq(bottomFace, topFace, frontFace, backFace, leftFace, rightFace)

// Robot Parts Definition
def head = Seq(
    Seq(
        Vector3D(-40, 120, size),
        Vector3D(40, 120, size),
        Vector3D(40, 200, size),
        Vector3D(-40, 200, size),
        Vector3D(-40, 120, size)
    )
)

def body = cube

def leftArm = Seq(
    Seq(
        Vector3D(-170, -60, size),
        Vector3D(-100, -60, size),
        Vector3D(-100, 80, size),
        Vector3D(-170, 80, size),
        Vector3D(-170, -60, size)
    )
)

def rightArm = Seq(
    Seq(
        Vector3D(100, -60, size),
        Vector3D(170, -60, size),
        Vector3D(170, 80, size),
        Vector3D(100, 80, size),
        Vector3D(100, -60, size)
    )
)

def leftLeg = Seq(
    Seq(
        Vector3D(-70, -250, size),
        Vector3D(-20, -250, size),
        Vector3D(-20, -100, size),
        Vector3D(-70, -100, size),
        Vector3D(-70, -250, size)
    )
)

def rightLeg = Seq(
    Seq(
        Vector3D(20, -250, size),
        Vector3D(70, -250, size),
        Vector3D(70, -100, size),
        Vector3D(20, -100, size),
        Vector3D(20, -250, size)
    )
)

val robot = body ++ head ++ leftArm ++ rightArm ++ leftLeg ++ rightLeg

// Transformation Helpers
def translateToOrigin(referencePoint: Vector3D, point: Vector3D): Vector3D = 
    Vector3D(
        point.x - referencePoint.x,
        point.y - referencePoint.y,
        point.z - referencePoint.z
    )

def translateBy(referencePoint: Vector3D, point: Vector3D): Vector3D = 
    Vector3D(
        point.x + referencePoint.x,
        point.y + referencePoint.y,
        point.z + referencePoint.z
    )

def rotateAroundY(angle: Double, point: Vector3D) = 
    Vector3D(
        point.x * Math.cos(angle) + point.z * Math.sin(angle),
        point.y,
        point.z * Math.cos(angle) - point.x * Math.sin(angle)
    )

def rotateAroundX(angle: Double, point: Vector3D) = 
    Vector3D(
        point.x,
        point.y * Math.cos(angle) - point.z * Math.sin(angle),
        point.y * Math.sin(angle) + point.z * Math.cos(angle)
    )

def rotateAroundZ(angle: Double, point: Vector3D) = 
    Vector3D(
        point.x * Math.cos(angle) - point.y * Math.sin(angle),
        point.x * Math.sin(angle) + point.y * Math.cos(angle),
        point.z
    )

def normalisePoint(point: Vector3D): Vector3D = {   
    return Vector3D(
        point.x / (canvasBounds.width * 0.5),
        point.y / (canvasBounds.width * 0.5),
        point.z / (canvasBounds.width * 0.5)
    )
}

def toWorld(point: Vector3D): Vector3D = {   
    return Vector3D(
        point.x * (canvasBounds.width * 0.5),
        point.y * (canvasBounds.width * 0.5),
        point.z * canvasBounds.width * 0.5
    )
}

def toPerspective(point: Vector3D): Vector3D = {
    return Vector3D(
        point.x / (point.z * Math.tan(viewAngleHalf)),
        point.y / (point.z * Math.tan(viewAngleHalf)),
        point.z
    )
}

def drawFace(face: Seq[Vector3D]): Picture = Picture.fromVertexShape { x =>
    x.beginShape()
    face.foreach { v =>
        x.vertex(v.x, v.y) 
    }
    x.endShape()
}

def renderFace(angle: Double, face: Seq[Vector3D]): Unit = {
    val transformedFace = face
        .map(translateToOrigin(Vector3D(0, 0, size + 100), _))
        .map(rotateAroundY(Math.toRadians(angle), _))
        .map(rotateAroundX(Math.toRadians(angle / 2), _))
        .map(translateBy(Vector3D(0, 0, size + 100), _))
        .map(normalisePoint) 
        .map(toPerspective)    
        .map(toWorld) 

    draw(drawFace(transformedFace))     
}

animateWithState(0) { angle =>
    erasePictures()

    robot.foreach { face =>
        renderFace(-angle, face)    
    }

    angle + 1
}