Basic Principles of Two-Dimensional Graphics (Introduction to Computer Graphics Using Java 2D and 3D) Part 1

This topic introduces basic concepts that are required for the understanding of two-dimensional graphics. Almost all output devices for graphics like computer monitors or printers are pixel-oriented. Therefore, it is crucial to distinguish between the representation of images on these devices and the model of the image itself which is usually not pixel-oriented, but defined as scalable vector graphics, i.e., floating point values are used for coordinates.

Raster Versus Vector Graphics

Before an object can be shown on a computer monitor or a printer, a model describing the object’s geometry is required, unless the object is an image itself. Modelling of geometrical objects is usually done in the framework of vector-oriented or vector graphics. A more complex object is modelled as a combination of elementary objects like lines, rectangles, circles, ellipses or arcs. Each of these elementary objects can be defined by a few coordinates, describing the location of the object, and some parameters like the radius for a circle. A very simple description of the house in Fig. 2.1a in terms of vector graphics is shown in Fig. 2.1b. The house can be defined as a sequence of points or vectors. It must also be specified within the sequence of points whether two neighbouring points should be connected by a line or not. Dotted lines in Fig. 2.1b refer to points in the sequence that should not be connected by a line.

The vector graphics-oriented description of objects is not directly suitable for the representation on a purely pixel-oriented device like an LCD monitor or printer. From a theoretical point of view, it would be possible to display vector graphics directly on a CRT1 monitor by running the cathode ray—or, in case of colour display, the three cathode rays—along the lines defined by the sequence of points and switch the ray on or off, depending on whether the corresponding connecting line should be drawn.


Original image, vector and pixel graphics

Fig. 2.1 Original image, vector and pixel graphics

In this case, the monitor might not be flicker free anymore since the cathode ray might take too long to refresh the screen for a more complex image in vector graphics, so that fluorescent spots on the screen might fade out, before the cathode ray returns. Flicker-free monitors should have a refresh rate of 60 Hz. If a cathode ray were to run along the contour lines of objects represented in vector graphics, the refresh rate would depend on how many lines the objects contain, so that a sufficiently fast refresh rate could not be guaranteed in this operational mode. Therefore, the cathode ray scans the screen line by line leading to a guaranteed and constant refresh rate, independent of the image to be drawn.

Computer monitors, printers and also various formats for storing images like bitmaps or JPEG are based on raster or raster-oriented graphics, also called pixel or pixel-oriented graphics. Raster graphics uses a pixel matrix of fixed size. A colour can be assigned to each pixel of the raster. In the simplest case of a black-and-white image a pixel takes one of the two values black or white.

In order to display vector-oriented graphics in the form of raster graphics, all geometrical shapes must be converted into pixels. This procedure is called scan conversion. On the one hand, this can lead to high computational efforts. A standard monitor has more than one million pixels. For each of them, it must be decided which colour to assign to it for each image. On the other hand, undesired aliasing effects occur in the form of jagged edges, known as jaggies or staircasing. The term aliasing effect originates from the field of signal processing and refers to artefacts, i.e., superficial undesired effects that can occur when a discrete sampling rate is used to measure a continuous signal. A grey-scale image can be viewed as a twodimensional signal. In this sense, a coloured image based on the three colours red, green and blue is nothing else than three two-dimensional signals, one for each colour.

Even if an image will be displayed in terms of raster-oriented graphics, it still has advantages to model and store it in a vector-oriented format. Raster graphics is bound to a specific resolution. Once the resolution is fixed, the full information contained in the vector-oriented image cannot be recovered anymore, leading to serious disadvantages, when the image is displayed on a device with a different resolution or when the image needs to be enlarged or scaled down. Figure 2.2 shows the tip of an arrow and its representation in the form of raster graphics for two different resolutions.

The tip of an arrow drawn as raster graphics in two different resolutions

Fig. 2.2 The tip of an arrow drawn as raster graphics in two different resolutions

An alternative representation for pixels

Fig. 2.3 An alternative representation for pixels

If only the more coarse pixel image in the middle is stored, it is impossible to reconstruct the refined pixel image on the right-hand side without additional information. One could only produce an image appearing in the same form as the one in the middle by simply identifying four pixels of the refined image with one pixel in the coarser image. If the quotient of the pixel resolution is not an integer number, the transformation from a raster graphics with one resolution to a raster graphics with another resolution becomes even more complicated and will lead to new aliasing effects, even if the new resolution is higher than the original one.

In most cases, when a pixel matrix is considered in this topic, each pixel is represented by a square between the lines of a grid as shown in Fig. 2.2. However, sometimes another representation is more convenient where pixels are illustrated as circles on the points where the lines of the grid cross. Figure 2.3 shows the pixel with the grid coordinates (5, 3).

The First Java 2D Program

Before modelling of two-dimensional objects is discussed in more detail, a short introduction into how Java 2D can be used to generate images in general is provided.

Fig. 2.4 The Java 2D API extends AWT

The Java 2D API extends AWT

It is not the aim of this topic to provide a complete introduction to Java 2D and Java 3D. Instead, the main intention of this topic is to enable even those readers with only very basic knowledge in Java to use and apply the more theoretical concepts of computer graphics immediately within the framework of Java 2D and Java 3D. For this reason, the example programs are kept as simple as possible and not all available options and settings will be explained in detail, in order to better focus on the main aspects and concepts. For readers who are already more familiar with Java programming the topic provides an introduction to Java 2D and 3D that enables the reader to study the more advanced options and possibilities of these two Application Programming Interfaces (APIs) with the help of specific literature and the API documentations.

Detailed information concerning Java 2D can be found in topics like [1, 2], in the API documentation and the Java tutorial, which are available on the Internet.

Java 2D is an API belonging to the kernel classes of the Java 2 (formerly JDK 1.2) and later platforms so that it is not necessary to carry out additional installations to use Java 2D classes, as long as a Java platform is installed on the computer.

Java 2D extends some of the AWT2 packages of Java by additional classes and also introduces new packages within AWT. Java 2D can be viewed as a component under Java’s graphics components AWT and Swing (see Fig. 2.4).

Although AWT is seldom used anymore, the introductory examples for Java 2D in this topic are based on AWT. The reason is that within AWT it is easily possible to program simple animations without the technique of double buffering that will be used later on in this topic.

AWT components that are displayed on the computer screen contain a paint method with a Graphics object as its argument. In order to use the facilities of Java 2D for the corresponding AWT component, it is necessary to cast this Graphics object into a Graphics2D object. The class Graphics2D within Java 2D extends the class Graphics. The following simple Java class, SimpleJava2DExample.java, demonstrates this simple casting procedure. In order to keep the printed code examples short, comments are only included in the programs that can be downloaded from the web site of this topic, but not in the printed versions.

Fig. 2.5 The result of the first Java 2D program

The result of the first Java 2D program

The result of this program is shown in Fig. 2.5.

tmpc009-7_thumb

The method add Window Listener, called in the constructor, enables the closing of the window by clicking on the cross in the upper right corner. The method uses a simple additional class MyFinishWindow.java, which can also be downloaded from the web site of this topic. The main method generates the corresponding window, defines the title of the window, determines its size by 350 pixels in width and 80 pixels in height and finally displays it. This structure of the main method will be used for all Java 2D examples in this topic. For other programs, it will only be necessary to replace SimpleJava2DExample by the corresponding class name and—if desired—to change the title of the window and its size.

The image or graphics to be displayed is defined within the paint method. The first line of this method will always be the same in all examples here: It carries out the casting of the Graphics object to a Graphics2D object. The remaining code lines in the paint method depend on what is to be displayed and will be different for each program. In the example here, only the text “Hello world” is printed at the window coordinates (30, 50).

When specifying window coordinates, the following two aspects should be taken into account.

•    The point (0, 0) is located in the upper left corner of the window. The window extends to the right (in the example program 350 pixels) and downwards (in the example program 80 pixels). This means that the y-axis of the coordinate system does not point upwards, but downwards since the pixel lines in the window are counted from the top to the bottom. How to avoid this problem of an inverted y-axis will be explained later on.

•    The window includes margins on all its four sides. Especially the upper margin, containing the title of the window, is quite broad. It is not possible to draw anything on or outside these margins within the paint method. Trying to draw an object on the margin or outside the window will not lead to an error or exception. The clipping procedure will simply make sure that the object or its corresponding part is not drawn. Therefore, when a window of a size of 350 x 80 pixels is defined as in the example program, a slightly smaller area is available for drawing. The width of the margins depends on the operating system platform. The example programs avoid this problem by defining a window that is large enough and by not drawing objects too close to any of the margins. The exact width of the margins can also be determined within the class, for instance within the paint method using

Insets ins = this.getInsets();

The width of the left, right, upper and lower margin in pixels is given by ins.left, ins.right, ins.top and ins.bottom, respectively.

The first example of a Java 2D program did not require any additional computations before the objects—in this case only text—could be drawn. For real graphics it is usually necessary to carry out more or less complicated computations in order to define and position the objects to be displayed. Java 2D distinguishes between the definition of objects and drawing objects. An object that has been defined will not be drawn or shown in the corresponding window, until a draw- or fill method is called with the corresponding object as argument. Therefore, Java 2D also differentiates between modelling objects based on vector graphics using floating point arithmetics and displaying or drawing objects on the screen based on raster graphics with scan conversion and integer arithmetics.

In order to keep the example programs in this topic as simple and understandable as possible, the computations required for defining and positioning the geometric objects are carried out directly in the paint method. For more complex animated graphics, i.e., for graphics with moving or changing objects, this can lead to flickering effects and also to the effect that the window might react very slowly, for instance when it should be closed while the animation is still running. Java assigns a high priority to the paint method so that other events like closing of the window cannot be carried out immediately. In order to avoid this undesired effect, one can carry out all computations to construct or position objects outside the paint method and instead call the repaint method only, when objects have to be drawn.

The double buffering technique, introduced later on in Sect. 4.2, provides an even better solution.

Next post:

Previous post: