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 Sampleable
s.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 Renderable
s internal coordinates to the physical coordinates of the raster.AbstractRenderable
(Javadoc) defines a skeleton class for implementing Renderable
s. 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 Renderable
s 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 Sampleable
s 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 Sampleable
s 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 Sampleable
s. 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
Renderable
sSampleable overlay(Sampleable... layers)
that builds composite Sampleable
nodes by overlaying any number of other Sampleable
components (which may be leaves or composites themselves).Renderable
s by stacking several Renderable
s as layers. The Renderables.overlay(Renderable...)
static factory method takes any number of Renderable
s 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 Renderable
s 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 Sampleable
s 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.