Task

Draw a   cuboid   with relative dimensions of    2 × 3 × 4. 



The cuboid can be represented graphically, or in   ASCII art,   depending on the language capabilities.

To fulfill the criteria of being a cuboid, three faces must be visible.

Either static or rotational projection is acceptable for this task.



Related tasks
 draw a sphere
 draw a rotating cube
 write language name in 3D ASCII
 draw a Deathstar


--
-- demo\rosetta\draw_cuboid.exw
-- ============================
--
-- Author Pete Lomax, August 2015
--  Translated from XPL0.
--  Ported to pGUI August 2017
--
--  Press space to toggle auto-rotate on and off,
--        cursor keys to rotate manually, and 
--        +/- to zoom in/out.
--
--  Note this uses simple orthogonal projection;
--            there is no perspective here!
--            (For that see DrawRotatingCube.exw)
--
with javascript_semantics
include pGUI.e

constant title = "Draw Cuboid"
Ihandle dlg, canvas, hTimer
cdCanvas cd_canvas

-- arrays: 3D coordinates of vertices
sequence x = {-2.0, +2.0, +2.0, -2.0,  -2.0, +2.0, +2.0, -2.0},
         y = {-1.5, -1.5, +1.5, +1.5,  -1.5, -1.5, +1.5, +1.5},
         z = {-1.0, -1.0, -1.0, -1.0,  +1.0, +1.0, +1.0, +1.0}

constant segments = {{1,2}, {2,3}, {3,4}, {4,1}, {5,6}, {6,7},
                     {7,8}, {8,5}, {1,5}, {2,6}, {3,7}, {4,8}}

atom Size = 50.0,       -- drawing size 
     Sz = 0.008,        -- tumbling speeds
     Sx =-0.013,        -- ""
     Sy = 0.005,        -- ""
     S = 2

procedure draw_cube(integer cx, cy)
    -- {cx,cy} is the centre point of the canvas
    integer farthest = largest(z,true)
    for s=1 to length(segments) do
        integer {va,vb} = segments[s],
                  bNear = not find(farthest,segments[s])
        cdCanvasSetForeground(cd_canvas, iff(bNear?CD_RED:CD_BLUE))
        cdCanvasSetLineStyle(cd_canvas, iff(bNear?CD_CONTINUOUS:CD_DASHED)) 
        atom x1 = x[va]*Size+cx,
             y1 = y[va]*Size+cy,
             x2 = x[vb]*Size+cx,
             y2 = y[vb]*Size+cy
        cdCanvasLine(cd_canvas,x1,y1,x2,y2)
    end for
end procedure

function canvas_action_cb(Ihandle canvas)
    cdCanvasActivate(cd_canvas)
    cdCanvasClear(cd_canvas)
    integer {w, h} = IupGetIntInt(canvas, "DRAWSIZE")
    draw_cube(floor(w/2),floor(h/2))
    cdCanvasFlush(cd_canvas)
    return IUP_DEFAULT
end function

function canvas_map_cb(Ihandle canvas)
    IupGLMakeCurrent(canvas)
    if platform()=JS then
        cd_canvas = cdCreateCanvas(CD_IUP, canvas)
    else
        atom res = IupGetDouble(NULL, "SCREENDPI")/25.4
        cd_canvas = cdCreateCanvas(CD_GL, "10x10 %g", {res})
    end if
--  cdCanvasSetBackground(cd_canvas, CD_PARCHMENT)
    cdCanvasSetBackground(cd_canvas, CD_BLACK)
    return IUP_DEFAULT
end function

function canvas_unmap_cb(Ihandle canvas)
    cdKillCanvas(cd_canvas)
    return IUP_DEFAULT
end function

function canvas_resize_cb(Ihandle /*canvas*/)
    integer {canvas_width, canvas_height} = IupGetIntInt(canvas, "DRAWSIZE")
    atom res = IupGetDouble(NULL, "SCREENDPI")/25.4
    cdCanvasSetAttribute(cd_canvas, "SIZE", "%dx%d %g", {canvas_width, canvas_height, res})
    return IUP_DEFAULT
end function

function key_cb(Ihandle /*ih*/, atom c)
    if c=K_ESC then 
        return IUP_CLOSE
    elsif c=K_UP then
        for i=1 to 8 do
            y[i] += z[i]*Sx*S   -- rotate vertices in Y-Z plane
            z[i] -= y[i]*Sx*S
        end for
    elsif c=K_DOWN then
        for i=1 to 8 do
            y[i] -= z[i]*Sx*S   -- rotate vertices in Y-Z plane
            z[i] += y[i]*Sx*S
        end for
    elsif c=K_LEFT then
        for i=1 to 8 do
            x[i] += z[i]*Sy*S   -- rotate vertices in X-Z plane
            z[i] -= x[i]*Sy*S
        end for
    elsif c=K_RIGHT then
        for i=1 to 8 do
            x[i] -= z[i]*Sy*S   -- rotate vertices in X-Z plane
            z[i] += x[i]*Sy*S
        end for
    elsif c='+' then
        Size = min(500,Size+5)
    elsif c='-' then
        Size = max( 10,Size-5)
    elsif c=' ' then
        IupSetInt(hTimer,"RUN",not IupGetInt(hTimer,"RUN"))
    end if
    IupUpdate(canvas)
    return IUP_CONTINUE
end function

function timer_cb(Ihandle /*ih*/)
    for i=1 to 8 do
        x[i] = x[i]+y[i]*Sz*S   -- rotate vertices in X-Y plane
        y[i] = y[i]-x[i]*Sz*S
        y[i] = y[i]+z[i]*Sx*S   -- rotate vertices in Y-Z plane
        z[i] = z[i]-y[i]*Sx*S
        x[i] = x[i]+z[i]*Sy*S   -- rotate vertices in X-Z plane
        z[i] = z[i]-x[i]*Sy*S
    end for
    IupUpdate(canvas)
    return IUP_IGNORE
end function

procedure main()
    IupOpen()
    canvas = IupGLCanvas("RASTERSIZE=640x480")
    IupSetCallbacks(canvas, {"ACTION", Icallback("canvas_action_cb"),
                             "MAP_CB", Icallback("canvas_map_cb"),
                             "UNMAP_CB", Icallback("canvas_unmap_cb"),
                             "RESIZE_CB", Icallback("canvas_resize_cb")})
--  dlg = IupDialog(IupVbox({canvas}),`TITLE="%s"`,{title})
    dlg = IupDialog(canvas,`TITLE="%s"`,{title})
    IupSetCallback(dlg, "KEY_CB",  Icallback("key_cb"))
    IupShow(dlg)
    IupSetAttribute(canvas, "RASTERSIZE", NULL)
    hTimer = IupTimer(Icallback("timer_cb"), 40)
    if platform()!=JS then
        IupMainLoop()
        IupClose()
    end if
end procedure

main()
