teaching machines

Homework 4 – Wireframe – due November 12

August 15, 2019 by . Filed under cs1, fall 2019, specifications.

Your objective in this homework is to acquaint yourself with conditional statements and loops, which enable you to write code that diverges and repeats. You will do this in the context of writing an application that produces a GIF of animated wireframe objects.

This assignment is more involved and less easy to test in small chunks than your previous assignments. Plan accordingly.

Wireframes

The essential task in this homework is to read or parse an animation described in a text file, draw each frame of the animation into an image, and collect up the images into an animated GIF. Let’s work through an example Wireframes file and see what animation it produces before we get into the details of the specification.

Here’s a modest Wireframes file that demonstrates all the functionality that your final program will support:

resolution 120 100
delay 1000
loop true

frame
background 230 230 230

object
color 0 128 255
dilation 2
vertex 20 10
vertex 20 90
vertex 100 90
vertex 100 10
endobject

object
color 255 0 255
dilation 5
vertex 40 25
vertex 40 45
vertex 50 45
vertex 50 25
endobject

object
color 255 0 255
dilation 5
vertex 70 25
vertex 70 45
vertex 80 45
vertex 80 25
endobject

object
color 255 128 0
dilation 2
vertex 50 70
vertex 70 70
endobject

endframe

frame
background 230 230 230

object
color 0 128 255
dilation 2
vertex 20 10
vertex 20 90
vertex 100 90
vertex 100 10
endobject

object
color 255 0 255
dilation 5
vertex 40 25
vertex 40 45
vertex 50 45
vertex 50 25
endobject

object
color 128 0 255
dilation 5
vertex 70 35
vertex 80 35
endobject

object
color 255 128 0
dilation 2
vertex 50 70
vertex 73 65
endobject

endframe

Let’s break this down. Consider the first few lines:

resolution 120 100
delay 1000
loop true

From these lines we gather that the animation will be rendered into a GIF that is 120 pixels wide and 100 pixels tall, there will be a delay of 1000 milliseconds between frames, and the animation will loop.

Next in the file is the first frame sandwiched between frame and endframe:

frame
background 230 230 230

object ...

endframe

This first frame has a light gray background. Within the frame are plotted four objects. Let’s examine only the first:

object
color 0 128 255
dilation 2
vertex 20 10
vertex 20 90
vertex 100 90
vertex 100 10
endobject

This object is described with four vertices, which happen to form a square. It is plotted in bluish lines that have been thickened or dilated twice. Though its impossible to determine its semantic meaning through the text alone, this object is a head. In general, objects have one or more vertices and can take on any shape. But only its perimeter, or wireframe, is plotted. The second and third objects are eyes, and the fourth a mouth. Altogether the frame looks like this:

To produce a coherent animation, the second frame retains all of the objects but changes some of them. The head and one of the eyes stay the same, but the other eye winks as the mouth is drawn upward. The two-frame sequence produces this animated GIF:

Helper Classes

There are several classes that will aid you on your journey. Ideally, you should skim their documentation and investigate their usage in books and tutorials. Here we provide just a brief overview of some of their relevant methods.

BufferedImage

The BufferedImage class manages pixel-based images. You can make a new image with this construction:

BufferedImage image = new BufferedImage(480, 320, BufferedImage.TYPE_INT_RGB);

This image has a resolution of 480×320. Each pixel will hold an RGB color. To copy the pixel at column c, row r to its right neighbor, we’d write:

int rgb = image.getRGB(c, r);
image.setRGB(c + 1, r, rgb);

This code will throw an exception if you reach beyond the dimensions of the image.

Color

The Color class is a handy bridge between an int representation of a color and its four channels: red, green, blue, and opacity or alpha. If you have the intensities of the four channels as ints, you can construct a new Color using one of its several constructors:

Color color = new Color(red, green, blue, alpha);

We can turn a Color instance into an int use the getRGB method:

int packedColor = color.getRGB();

Suppose you instead have an int representation of the color already, but you need its four channels separated. You can decompose the int by way of the Color class:

Color color = new Color(packedColor);
int red = color.getRed();
int green = color.getGreen();
int blue = color.getBlue();
int alpha = color.getAlpha(); // always returns 255

But be careful here. The Color constructor invoked here ignores the alpha stored in the int representation for an unknown reason. If you want the alpha channel to get unpacked, you need a two-parameter version of the Color constructor:

Color color = new Color(packedColor, true);
int alpha = color.getAlpha(); // that's better!

The BufferedImage class only works with the packed int form of colors. We often convert its ints to the friendlier Color class because of its useful methods.

ImageIO

To test your code in small chunks, it will be helpful to read and write BufferedImages to disk, as we do here:

try {
  BufferedImage image = ImageIO.read(new File("/Users/foobag/Desktop/image.png"));
  ImageIO.write(image, "png", new File("/Users/foobag/Desktop/image.png"));
} catch (Exception e) {
  throw RuntimeException(e);
}

You’ll need to edit the paths to point to your actual destination directory.

When we deal with files, we are likely to encounter FileNotFoundException or IOException. Java forces us to acknowledge these exceptions, and we deal with them here by turning them into a RuntimeException, which lets them bubble up and halt our program.

GifSequenceWriter

Java by itself can’t produce animated GIFs, but a GifSequenceWriter class that can do so has been bundled into the hw4.specchecker package. You can create one like so:

GifSequenceWriter gif = new GifSequenceWriter(new File("/Users/foobag/Desktop/movie.gif"));
gif.setDelay(100);
gif.setLooping(true);
gif.appendFrame(image0);
gif.appendFrame(image1);
gif.appendFrame(image2);
gif.close();

When you reference GifSequenceWriter for the first time in your code, IntelliJ will show it in red because it’s not a class it knows about yet. Click on the red lightbulb icon that shows up and select Add library hw4.jar to classpath.

Okay, now we’re ready for the detailed specification!

Requirements

Complete the classes described below. Place all classes in package hw4. Make all methods static.

Main

Write class Main with a main method, which you are encouraged to use to test your code. Nothing in particular is required of it, but it must exist.

DrawingUtilities

Write class DrawingUtilities with the following methods:

ImageUtilities

Write class ImageUtilities with the following methods:

Wireframes

Write class Wireframes that handles the parsing of an animation file. Its methods are listed below from independent to dependent order. The last method in the list is what depends on all those above it. You may want to read the list from bottom to top, but we recommend you implement them from top to bottom, testing each one independently to minimize pain and suffering.

Extra

For an extra credit participation point, compose your own animation and share it on Piazza under folder ec4 by the due date. To be eligible, your animation shouldn’t look like it was scrapped together in as little time and with creative effort as possible. The submission garnering the most votes will be honored in some way.

Here’s your instructor’s submission:

And here’s the Wireframes file that produced this:

resolution 181 100
delay 250

frame
background 100 100 255
object
dilation 1
color 255 255 255
vertex 10 50
vertex 30 30
vertex 50 20
vertex 60 20
vertex 80 40
vertex 90 30
vertex 100 40
vertex 120 20
vertex 130 20
vertex 150 30
vertex 170 50
vertex 130 30
vertex 120 30
vertex 100 50
vertex 80 50
vertex 60 30
vertex 50 30
endobject
endframe

frame
background 100 100 255
object
dilation 1
color 255 255 255
vertex 20 30
vertex 50 20
vertex 80 50
vertex 90 40
vertex 100 50
vertex 130 20
vertex 160 30
vertex 130 30
vertex 100 60
vertex 80 60
vertex 50 30
endobject
endframe

frame
background 100 100 255
object
dilation 1
color 255 255 255
vertex 10 50
vertex 30 30
vertex 50 20
vertex 60 20
vertex 80 40
vertex 90 30
vertex 100 40
vertex 120 20
vertex 130 20
vertex 150 30
vertex 170 50
vertex 130 30
vertex 120 30
vertex 100 50
vertex 80 50
vertex 60 30
vertex 50 30
endobject
endframe

frame
background 100 100 255
object
dilation 1
color 255 255 255
vertex 60 90
vertex 50 70
vertex 60 40
vertex 80 30
vertex 90 20
vertex 100 30
vertex 120 40
vertex 130 70
vertex 120 90
vertex 120 60
vertex 100 40
vertex 80 40
vertex 60 60
endobject
endframe

Submission

To check your work and submit it for grading:

  1. Run the SpecChecker by selecting hw4 SpecChecker from the run configurations dropdown in IntelliJ IDEA and clicking the run button.
  2. Fix problems until all tests pass.
  3. Commit and push your work to your repository.
  4. Verify on Gitlab that your submission uploaded successfully by adding the comment test hw4 to any commit. You will receive an email of the SpecChecker results.

A passing SpecChecker does not guarantee you credit. Your grade is conditioned on a few things: