Project 3: JPS, A Java To PostScript Translator

6.005 Elements of Software Construction
Spring 2008
Due: Thursday, March 20 and Thursday, April 3

Problem

PostScript is a programming language designed primarily for describing the layout of printed pages. A PostScript program (stored as text files with the extension .ps) is interpreted by a viewer (such as Ghostview). Interpreting a program results in a set of strokes drawn on the page (either on your screen, or on real paper in the printer). PostScript programs can also be translated into other popular page layout formats such as PDF and Word. For a brief history of PostScript, see this wikipedia article. If you're interested in learning the difference between PostScript and PDF, Adobe published an article on the subject.

In this project, you will implement a Java library that we will call JPS, short for "Java to PostScript." JPS will allow its user to specify drawings at a high level of abstraction, and output the drawings as PostScript. JPS consists of:

Purpose

The purpose of this project is to help you develop your understanding of programming with immutable datatypes, and viewing a datatype (or collection of datatypes) as a kind of language. In designing and implementing the transformations on the PostScript commands, you'll get practice using the design patterns that we've been teaching, such as Visitor and Interpreter.

Specification

Shape language

The JPS shape language relies on the following fundamental notions:

JPS is based on a language of immutable shapes, that are either basic or compound.

Basic shapes

Basic shapes are primitive shapes that can be created without reference to any other shapes.

  1. Circle(double radius). Creates a circle with the given radius. The height and width of a circle are both 2*radius.

  2. Polygon(int numSides, double sideLength). Creates a regular polygon with the given number of sides, each of the given length, oriented so that its lowermost side is horizontal.

  3. Rectangle(double width, double height). Creates a rectangle of the given width and height.

  4. Spacer(double width, double height). Like a rectangle, but without drawn borders. A spacer is not visible on the page.

  5. Square(double sideLength). Equivalent to Polygon(4, sideLength).

  6. Triangle(double sideLength). Equivalent to Polygon(3, sideLength).

Compound shapes

Compound shapes are shapes that are constructed from one or more other shapes, which may themselves be basic or compound.

JPS to PostScript translator

JPS lets the user translate any shape into a sequence of PostScript commands. The user can specify the name of the resulting file. The resulting file is a legal PostScript file that can be previewed on screen or printed on paper.

Tasks

All your code in this project should use immutable datatypes. You will need use some mutable types from the Java library for writing output to files, but should avoid mutation everywhere else.

  1. Prepare. Complete the lab.
  2. Design the shape language, expressing it as a collection of recursive datatype definitions.
  3. Design your JPS, expressing your ideas using a class outline, a module dependency diagram, and any additional explanatory text that you feel is necessary. Explain the advantages and disadvantages of your design by comparing it to at least one alternative, fleshing out the alternative (with a class outline and MDD) to the extent necessary to make your points clear and easily understood.
  4. Extend. Design two or more nice shapes of your own and generate PostScript from them. You'll probably want to write some classes that build on the shape language. For example, you might implement a class Skylines that contains methods returning randomized skylines with the number/height/shape of buildings specified as input arguments to the methods. Or you might implement a class Fractals that creates some fractal figures with a recursion limit specified by the user. These are just examples; it's entirely up to you. A prize will be awarded for the best shape.
  5. Implement your design of JPS.
  6. Test. Design and implement a test strategy for this project. In addition to the JUnit test cases themselves, you should give a brief commentary explaining your strategy.
  7. Demonstrate. At your grading meeting, present your JPS to your TA. The presentation must include: (1) an overview and justification of the design choices, (2) a walk-through of the JPS, and (3) a demo of the postscript files.
  8. Reflect. Write a brief commentary saying what you learned from this experience. What was easy? What was hard? What was unexpected? Briefly evaluate your solution, pointing out its key merits and deficiencies. Was your design flexible and modular enough to allow easy inclusion of more features? How could you make it more flexible? Critique the specification of the shape language. Is the language expressive enough to create interesting drawings? Are the shape abstractions well-designed, or not? Do they make certain drawings easy/difficult to create? If you were to design the shape language from scratch, what would you do differently?
  9. Comment on your collaboration in your LNB, as outline in the LNB guide online (here)

Infrastructure

Package postscript.commands

The package postscript.commands in the Eclipse project includes a set of classes that represent PostScript commands. These classes have very little functionality in them -- they are little more than wrappers that allow you to create commands and print out their string representation. You may use these classes if you want to help generate a PostScript file. The classes may contain more commands than you will use, or you may need to add new commands not included.

Deliverables and Grading

There are two deadlines for this project. On March 20, you will hand in a design document that includes:
  1. Your shape language.
  2. Your design analysis
You should both commit your design documents to your pair repository and put a hard copy in the LNB box for your section by 5PM on Thrusday.

On April 3 you need to hand in:

  1. Your implementation
  2. Your test suite
  3. Your design extensions
  4. Your reflections
  5. Your (individual) LNB comments

You should both commit your documents and code to your pair repository and put a hard copy in the LNB box for your section by 5PM on Thursday.

90% of your grade will be allotted to the design and implementation, and 10% to the example shapes you created. Of the 90%, 30% will be allotted to the design of your recursive types and your design critique, 40% to the code (half for structure and half for correctness), and 20% to the testing strategy and test cases.

Hints

  1. The standard way to structure an implementation of a language is to have a collection of classes for representing the syntactic objects of the language (in this case, the shapes), and some visitors that perform transformations with these objects. For JPS, these visitors might compute the width and height of a shape, and convert a shape into a PostScript program.
  2. The "..." syntax in the compound shape definitions above is Java's vararg construct. Other Java constructs that you are likely to find useful in this project are enumerations and generic types.
  3. When implementing a visitor that generates a PostScript program, we found it useful to (1) assume, on entry to each visiting method, that the point around which the shape is to be centered has already been correctly set; and (2) for basic shapes, to draw the shape by starting a new path, drawing, closing the path, and calling stroke; and (3) for some visitor methods, to use gsave on entry and grestore before exit. These are only suggestions, however, and you might find a different (and maybe better) approach.
  4. The width and height of the bounding box for Polygon(n, e) is given by the following formulas:

  5. In PostScript, use showpage to finally draw the current page and create a new page.

Why JPS?

PostScript includes commands for drawing lines and arcs, rotation, scaling, and abstraction via function definition. Why not just create a library of PostScript definitions that a user can import and call directly in PostScript? The answer to this question has two parts. First, a library like JPS would come in very handy as a part of a word processing or drawing editor written in Java. The developers of such an editor could use JPS to implement an "export as PostScript" functionality in the editor. Second, JPS's design separates the shape language from its translation to PostScript, and this separation would make it easily extendable so that it could produce drawings in other target formats, different from PostScript.

References