The main goals of this assignment are to gain experience with the composite and adaptor patterns. Before writing code of your own, you will likely want to look over the code that is provided. Most of this you should have seen before, either in the previous problem set or in lecture, but there are a few things that are different or new: The This problem set builds on the previous problem set—it depends on the In lectures and the previous problem sets we represented scalable graphics using the The first part of your task is to implement a class Note that the In addition to implementing the These constructors are documented in the In the last problem set, you wrote a static method We need a similar method for constructing composite In class Modify the So far we have rendered only circles and combinations of circles. Time for something different: Rectangles! For this last part, you will implement an adaptor that works in the other direction, allowing a Try the following experiment in Repeat the above experiment, but this time adapt the Composites and Adaptors
2 Getting Started
Grade08 is similar to the file that I will use with the autograder. It should not compile right now, as it mentions code that you haven’t written yet. However, if you problem set is completed correctly then Grade08.java should compile and the tests should pass.AffineTransformation (Javadoc) defines a class for 2-D affine transformations, which include scaling, rotation, translation, and shearing. Affine transformations can be specified as a matrix using the AffineTransformation.matrix static factory method. There are additional static factories for more specific kinds of transformations.Transformable (Javadoc) defines an interface for objects that affine transformations can be applied to. This includes points, bounding boxes, and Sampleables.Renderable (Javadoc) defines an interface for objects that know how to render themselves to a raster. When rendering, the client may provide an affine transformation to map from the Renderables internal coordinates to the physical coordinates of the raster.AbstractRenderable (Javadoc) defines a skeleton class for implementing Renderables. It provides the getBoundingBox() and transform(AffineTransformation) methods, so that subclasses need only define a rendering method.Renderables (Javadoc) defines a static factory method for making circle Renderables and a static factory method that adapts a Sampleable for use as a Renderable.CirclesDemo class contains some commented-out code that will exercise the code you need to write, once it’s ready. (But this is no substitute for actual testing.)IntegerPoint, DoublePoint, and Colors classes that you implemented. You are free to use your implementations of these classes, but if you prefer to use mine, compiled binary class files are available in pset08.jar.2.1 Renderables
Sampleable interface, which provides a way for a renderer to query such an object about its color at different points to nearly arbitrary precision. This provides a lot of control over how Sampleables are composed, because Sampleable decorators can wrap a Sampleable in order to modify the points of queries, to modify the resulting color, or even to turn a single color query into multiple queries on the decorated object. This is flexible, but also inefficient. In this problem set, we will explore another approach, the Renderable interface for objects that know how to render themselves to a Raster.Renderable objects, like Sampleable objects, know their bounding box, but unlike Sampleables they take an active role in rendering. Renderable has a void method render(Raster) that renders the object to the given Raster. The Renderable is rendered using a direct mapping of its internal coordinate system to the Raster’s pixels, just as SimpleSampler does for Sampleables. To support scaling, rotation, and other tranformation, Renderable also provides a more generalrender(AffineTransformation, Raster) method that allows providing an affine transformation to map the Renderable’s coordinates to the Raster. See the implementation of Sampleables.circle(Point<Double>, double, Color) for an example of how this works.3 Your Task
3.1 The
OverlayRaster ClassOverlayRaster, which modifies the behavior of the setRGBA(Point<Integer>, int) method to handle alpha in the color being set. In particular, rather than replacing the value of the given pixel, it overlays the given color over the existing color of the pixel. This enables rendering (partially) transparent objects directly to a raster that already contains whatever background should show through them.setRGBA method takes an int color value, not a Color object, so there is no direct way to overlay two colors. However, it can be done by temporarily converting the int representation into Color objects.Raster interface, OverlayRaster must have two public constructors:
public OverlayRaster(Raster base) constructs an OverlayRaster that stores its pixels in the given Raster. In particular, setting pixels in base should affect the corresponding pixels as viewed via the resulting OverlayRaster, and vice versa.public OverlayRaster(int width, int height) uses a new ArrayRaster of the given dimensions to store its pixel data.OverlayRaster Javadoc.
OverlayRaster class, as described above. Be sure to test your code thoroughly.3.2 Overlaying
RenderablesSampleable overlay(Sampleable... layers) that builds composite Sampleable nodes by overlaying any number of other Sampleable components (which may be leaves or composites themselves).Renderables by stacking several Renderables as layers. The Renderables.overlay(Renderable...) static factory method takes any number of Renderables and stacks them front to back, which means that when they are rendered the front of the array is rendered on top of the back of the array.
Renderables, write a public static method Renderable overlay(Renderable... layers) that overlays the layers front-to-back. Rendering to an OverlayRaster should result in transparency in the layers being displayed properly. Be sure to test your code.CirclesDemo class to use your OverlayRaster by uncommenting line 16, and by changing the circles() method to return the overlaid circles using your overlay method. Running the program should demonstrate the partial transparency enabled by OverlayRaster.3.3 Rendering Rectangles
Renderables.rectangle is a static factory method that constructs a renderable rectangle with its sides at the given coordinates. (See the implementation of Renderables.circle to get the idea of how to do this.)
Renderables, write a public static method Renderable rectangle(double top, double bottom, double left, double right, Color color) that returns a Renderable to render the specified rectangle in the specified color. Be sure to test your code.3.4 Adapting between Sampling and Direct Rendering
Sampleable and Renderable distinctly different approaches to representing scalable, composable graphics. They are not equivalent, but close enough that it is generally possible to adapt a graphic element represented using one interface to be usable via the other. For example, see the static factor method Renderables.renderable(Sampleable), which takes a Sampleable and adapts it for use as a Renderable. Its render method works by sampling the Sampleable and rendering the resulting pixel colors to the given Raster.Renderable to be used as a Sampleable. Probably the most straightforward way to do this is to allocate a private OverlayRaster large enough to fit the Renderables bounding box and render into it. Then use the colors in the Raster to answer getColorAt requests. Note that the resolution of the Raster determines what resolution can be distinguished by getColorAt. Your adaptor should use a Raster with one pixel per 1.0 units in the Renderable’s coordinates.
Sampleables, write a public static method Sampleable sampleable(Renderable) that adapts the given Renderable to be used as a Sampleable. Be sure to test your code.CirclesDemo.java. In the CirclesDemo.render method, create a Sampleable that contains an adapted Renderable circle using your adaptor. Then scale up the resulting Sampleable (see Transformable.scale(double)) by a factor of four and sample it to the raster parameter. You should see pixelation because the Raster used in your adaptor doesn’t contain enough information to sample when scaled up. However, this can be fixed by forcing the Renderable to be rendered at a higher resolution.
Sampleables, uncomment method sampleable(double, Renderable), which uses your sampleable method from the previous item to create Sampleables that adapt the Renderable at a higher resolution.Renderable to a Sampleable using sampleable(double, Renderable) with a factor of 4.0. The pixelation should be eliminated.