Java 2D Graphics public static final int SEG_LINETO This segment type is a straight line, drawn from the last point in the path. public static final int SEG_QUADTO This segment type is a curved line that is represented by a quadratic (second-order) equation. The segment is fully described by two endpoints and a control point, which determines the curve’s tangents at its endpoints. The previous point in the path is used as the first endpoint. The other endpoint and the control point need to be specified. Imagine an invisible string running between the control point and the curve as you move the control point around, the curve is pulled toward the control point. Figure 3.4 shows a few quadratic curves. Figure 3.5 shows the same quadratic curves with the endpoints, control points, and tangent lines shown. Figure 3.4. Quadratic curves Figure 3.5. Endpoints, control points, and tangent lines of quadratic curves public static final int SEG_CUBICTO This segment type represents a B zier cubic curve. A cubic curve is basically a quadratic curve with an additional control point; mathematically, it is described by a third-order equation and can be specified with two endpoints and two control points. Each control point determines the tangent of the curve at one of the endpoints. Figure 3.6 shows a few cubic curves, and Figure 3.7 shows the endpoints, control points, and tangent lines of the same curves. Figure 3.6. Cubic curves Figure 3.7. Endpoints, control points, and tangent lines of cubic curves page 31
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Tomcat Web Hosting services
Java 2D Graphics 3.2.2 java.awt.geom.PathIterator A Shape’s border is represented by something called a path. A path is simply a series of instructions, like a set of directions for getting from one place to another. The instructions describe each segment, or piece, of the path. You could describe the outline of a square with a set of instructions like this: 1. Move to 0, 0. 2. Draw a line to 72, 0. 3. Draw a line to 72, 72. 4. Draw a line to 0, 72. 5. Draw a line back to 0, 0. In Java 2D, the segments of a path are encapsulated by the java.awt.geom.PathIteratorinterface. You can get an object that describes the outline of a Shape by calling the Shape’s getPathIterator() method. PathIterator allows you to walk through the segments of a path. A Path-Iterator is designed to work like a java.util.Enumeration. When you first obtain a PathIterator, it is positioned at the beginning of the path, and you can move through the different segments of the path until you reach the end of the path. Note that PathIterator is read-only: it describes a path but doesn’t let you change it. 3.2.2.1 Path segments The PathIterator interface defines constants representing the five possible segment types: public static final int SEG_MOVETO This segment type is used to update the location of the path without drawing anything. page 30
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Tomcat Web Hosting services
Java 2D Graphics A related set of methods tests to see if any part of a rectangle intersects the interior of the Shape: public abstract boolean intersects(double x, double y, double w, double h) public abstract boolean intersects(Rectangle2D r) These methods return true if any part of the given rectangle is in the interior of the Shape. Finally, a Shape can describe its own outline, using the getPathIterator() methods. These methods return a PathIterator, which I’ll talk about later in this chapter. For now, just think of it as an object that describes a geometric outline. The getPathIterator() methods accept a transform object that can be used to move, rotate, or otherwise modify the PathIterator that is returned. I’ll cover transformations in detail in Chapter 5. public abstract PathIterator getPathIterator(AffineTransform at) This method returns a PathIterator representing the Shape’s outline, transformed by the given AffineTransform. You can pass null for this parameter if you don’t wish to transform the outline. public abstract PathIterator getPathIterator(AffineTransform at, double flatness) This method returns a flattened PathIterator representing the Shape’s outline, transformed by the given transform. A flattened path contains only straight line segments. The flatness parameter is the maximum allowed distance from the original path to the flattened version of the path. You’ll probably never have to call this method yourself. (See the sidebar.) Flattened Shapes A flattened path is a path whose curved line segments have been approximated by multiple straight line segments. Your Graphics2D implementation may not be able to draw or fill shapes with curved line segments, so a flattened path may be used to render shapes that have curved line segments. In fact, the 2D API includes a class, java.awt.geom.FlatteningPathIterator, that does the work of flattening a path. Normally, path flattening happens behind the scenes, and you won’t ever have to worry about the details. All the geometric classes in Java 2D implement the Shape interface, as illustrated in Figure 3.3. Directly or indirectly, every geometric class in Java 2D implements the Shape interface. This means that they can all be passed to Graphics2D’s draw() and paint() methods. Figure 3.3. The Shape interface and its progeny page 29
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Tomcat Web Hosting services
Java 2D Graphics line segments and multiple sub-shapes, as you’ll see later. 3.2.1 java.awt.Shape The java.awt.Shape interface is one of the common currencies of the 2D API. It contains four groups of methods: getBounds(), contains(), intersects(), and getPathIterator(). The getBounds() methods return rectangles that completely enclose a Shape: public abstract Rectangle getBounds() This method returns a java.awt.Rectangle that completely encloses the Shape. Rectangle stores its coordinates as integers. public abstract Rectangle2D getBounds2D() This method returns a java.awt.geom.Rectangle2D that completely encloses the Shape. Rectangle2D returns its coordinates as doubles. This method provides a higher precision bounding box than getBounds(); you should use it unless you have a specific reason to work with integer coordinates. The initial release of Java 2 (formerly JDK 1.2) contains a bug in Arc2D’s implementation of . The returned rectangle is the right size but in the wrong place. This bug is fixed in JDK 1.2.1. Figure 3.2 shows the bounds rectangles of a few shapes. Figure 3.2. Bounds rectangles A Shape has an interior and an exterior. You can see if a point or rectangle is inside the Shape using the contains() methods: public abstract boolean contains(double x, double y) public abstract boolean contains(Point2D p) These methods return true if the Shape contains the given point. This can actually be pretty complicated, as you can see from the right side of Figure 3.2. I’ll explain how the interior of a shape is determined later in this chapter. public abstract boolean contains(double x, double y, double w, double h) public abstract boolean contains(Rectangle2D r) These methods return true if the given rectangle is completely in the interior of the Shape. page 28
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Tomcat Web Hosting services
Java 2D Graphics The inner child class Point2D.Double has two constructors: public Point2D.Double() This constructor creates a Point2D.Double at the coordinates 0, 0. public Point2D.Double(double x, double y) This constructor creates a Point2D.Double at the given coordinates. Point2D.Float has a similar pair of constructors, based around floats instead of doubles: public Point2D.Float() public Point2D.Float(float x, float y) Furthermore, Point2D.Float provides an additional setLocation() method that accepts floats instead of doubles: public void setLocation(float x, float y) This method sets the location of the point using the given coordinates. Why use floats instead of doubles? If you have special concerns about the speed of your application or interfacing with an existing body of code, you might want to use Point2D.Float. Otherwise, I suggest using Point2D.Double, since it provides the highest level of precision. 3.2 Shapes and Paths As you saw in Chapter 2, the Graphics2D class is the rendering engine for the Java 2D API. Two of its basic operations are filling shapes and drawing their outlines. But Graphics2D doesn’t know much about geometry, as the song says. In fact, Graphics2D only knows how to draw one thing: a java.awt.Shape. The Shape interface represents a geometric shape, something that has an outline and an interior. With Graphics2D, you can draw the border of the shape using draw(), and you can fill the inside of a shape using fill(). The java.awt.geom package is a toolbox of useful classes that implement the Shape interface. There are classes that represent ellipses, arcs, rectangles, and lines. First, I’ll talk about the Shapeinterface, and then briefly discuss the java.awt.geom package. If You’re an Old Dog You probably remember that the Graphics class had methods for drawing and filling simple shapes: drawRect(), drawOval(), drawArc(), fillRect(), fillOval(), fillArc(), etc. Because Graphics2D is a subclass of Graphics, you can still call these methods to render shapes. In some cases, it’s easier to call one of these methods, because you can render a shape in a single step. On the other hand, these methods use only integer coordinates, and they don’t allow you to reuse shapes. Furthermore, the most complex shape that Graphics supports is a polygon defined with straight line segments. The Shape interface also supports curved page 27
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Java Web Hosting services
Java 2D Graphics The original java.awt.Point, which dates back to JDK 1.0, stores the coordinates as integers. Java 2D provides Point2D.Float and Point2D.Double for higher precision. Find Your Inner Child What’s an inner child class? An inner class , introduced to the Java language in JDK 1.1, is a class that is defined inside another class. For example, a class called Painter might have an inner class called Raphael. The full name of that inner class is Painter.Raphael. A child class is a class that extends another class. In the AWT, for example, classes like Button and Canvas extend the Component class. An inner child class combines both of these techniques: it is a class that is defined inside its own superclass. Inner child classes are a recurring theme in the java.awt.geom package. The Point2D class, for example, has two inner child classes, called Point2D.Double and Point2D.Float. For more information on inner classes, see Java in a Nutshell, by David Flanagan (O’Reilly), or Exploring Java, by Pat Niemeyer and Josh Peck (O’Reilly). You can either set a point’s location or find out where it is: public abstract void setLocation(double x, double y) This method sets the position of the point. Although it accepts double values, be aware that the underlying implementation may not store the coordinates as double values. public abstract void setLocation(Point2D p) This method sets the position of the point using the coordinates of another Point2D. public abstract double getX() This method returns the x (horizontal) coordinate of the point as a double. public abstract double getY() This method returns the y (vertical) coordinate of the point as a double. Point2D also includes a handy method for calculating the distance between two points: public double distance(double PX, double PY) Use this method to calculate the distance between this Point2D and the point specified by PX and PY. public double distance(Point2D pt) This method calculates the distance between this Point2D and pt. page 26
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Java Web Hosting services
Java 2D Graphics coordinates into 1 physical inch. Let’s say, for example, that you create a rectangle that is 144 User Space coordinates wide and 72 User Space coordinates high. The default transformation into Device Space for a monitor will map User Space directly to Device Space. Since monitors have (more or less) 72 pixels per inch, the rectangle will be 2 inches wide and 1 inch high. If you draw the same rectangle on a 300 DPI printer, the default transformation will convert the rectangle into a 600 by 300 pixel rectangle. The end result will still be a rectangle that is 2 inches wide and 1 inch high. In general, you don’t ever have to worry about the details of a particular device. Your applications live in User Space. As long as you remember that User Space, by default, has 72 coordinates per inch, Java 2D will ensure that everything is the right size on your output devices. Chapter 3. Geometry Java 2D allows you to represent any shape as a combination of straight and curved line segments. This chapter describes the Java 2D classes that represent geometric shapes. You’ll learn about the following topics: classes that represent points the two central interfaces for geometric shapes: Shape and PathIterator 2D’s toolbox of shapes in the java.awt.geom package 2D’s support for combining shapes with each other 3.1 Points The java.awt.geom.Point2D class encapsulates a single point (an x and a y) in User Space. It is the most basic of the Java 2D classes and is used throughout the API. Note that a point is not the same as a pixel. A pixel is a tiny square (ideally) on a screen or printer that contains some color. A point, by contrast, has no area, so it can’t be rendered. Points are used to build rectangles or other shapes that have area and can be rendered. Point2D demonstrates an inheritance pattern that is used throughout java.awt.geom. In particular, Point2D is an abstract class with inner child classes that provide concrete implementations. Figure 3.1 shows Point2D’s family tree. It’s a pattern that you’ll see again and again in the java.awt.geompackage. Figure 3.1. Point2D family of classes Point2D represents a point in User Space, but it doesn’t specify how the point’s coordinates are stored. The subclasses provide different levels of precision for storing the coordinates of the point. page 25
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Tomcat Web Hosting services
Java 2D Graphics For example, you might place the new shape behind the other elements on the drawing surface. The 2D API’s compositing rules are covered in Chapter 5. 2.5 Coordinate Space Java 2D objects live in a plane defined by Cartesian coordinates. This plane is called User Coordinate Space, or just User Space. When objects are drawn on a screen or a printer, User Space coordinates are transformed into Device Space coordinates. Device Space corresponds to a particular monitor or printer usually, one unit in Device Space corresponds to one pixel of a device. By default, User Space and Device Space are aligned, with the x and y axes oriented as shown in Figure 2.7. The x axis increases from left to right, and the y axis increases from top to bottom. The origin is placed at the upper left corner of the drawing surface. This applies for any device, where left, right, top, and bottom are defined in terms of the device itself the sides of a monitor, for example, or the orientation of a sheet of paper in a printer. Note that the y axis is aligned so that it increases as you go down this may be the opposite of what you were expecting. Figure 2.7. Device Space coordinate system Although User Space and Device Space are aligned by default, some scaling must take place to ensure that objects are drawn the same size, regardless of the output device. Device Space is determined by the resolution of a particular device. A monitor, for example, typically has about 72 pixels per inch, while a laser printer generally has 300 or 600 pixels per inch (or DPI, dots per inch). User Space is converted to Device Space when objects are drawn. A transformation is used to convert from one system to the other. The default transformation converts 72 User Space page 24
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Tomcat Web Hosting services
Java 2D Graphics each pixel in the upper left corner of the same shape. The grid lines and the ideal shape are superimposed for clarity. You can tell that the rasterizer used antialiasing because there is a range of values between 0.0 and 1.0. Figure 2.5. The rasterizer produces an alpha value for every pixel The rasterizer produces alpha values from ideal shapes, but that’s only part of the story. Rendering is the process of determining the color for pixels. A technique called compositing is used to decide how to translate alpha values into color information. 2.4 Compositing Once the rasterizer has generated alpha values for an ideal shape, there are several ways to use them to modify the drawing surface of a Graphics2D. A compositing rule determines how the colors of a new graphics primitive are combined with the existing colors on a drawing surface, as shown in Figure 2.6. In Figure 2.6, the alpha values are used to blend colors between the background color, white, and the color that is used to fill the shape, black. This is probably the most intuitive compositing rule, but there are other possibilities. Conceptually, at least, the rasterizer produces a set of alpha values for the new shape that is the same size as the drawing surface on which the shape will be rendered. Then this set of alpha values and the desired color of the new shape are combined, pixel by pixel, with the drawing surface. The equation that is used to combine these values is the compositing rule. Figure 2.6. Adding to a drawing surface page 23
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Tomcat Web Hosting services
Java 2D Graphics The better method for filling a shape involves a little more work. The basic idea is to calculate the intersection of the shape with each pixel of the output device. Pixels are colored in proportion to the amount they are covered by the shape. This reduces the jaggies that are symptomatic of aliased rendering. Not surprisingly, this technique is called antialiasing. Figure 2.4 shows the same shape as Figure 2.3, but rendered with antialiasing. The pixels on the edge aren’t just black or white; they’re varying shades of gray. Figure 2.4. Antialiased rendering Fortunately, the 2D API takes care of all the details for you. You just need to specify whether you want antialiasing, using rendering hints. 2.3.2 The Rasterizer Inside the rendering pipeline, a rasterizer takes ideal shapes and produces coverage values for each pixel. The coverage values represent how much of each pixel is covered by the shape. These coverage values are called alpha values. Each pixel has its own alpha value. The collection of all alpha values in an image is sometimes called the alpha channel. A pixel, then, is defined by a color and an alpha value. Intuitively, the alpha value indicates the transparency of the pixel. You can even think of the alpha value as part of the pixel’s color. As you’ll find out, colors are sometimes defined with an associated alpha value. In this context, the alpha value indicates the transparency of the color itself. Alpha values typically range from 0.0, for no coverage, to 1.0, which represents full coverage. In Figure 2.3, the rasterizer did not use antialiasing and produced either 0.0 or 1.0 for the alpha values. In Figure 2.4, antialiasing was used and the rasterizer produced a range of alpha values from 0.0 on the outside of the shape to 1.0 in the interior of the shape. Figure 2.5 shows the alpha values for page 22
Note: If you are looking for good and high quality web space to host and run your application check Lunarwebhost Tomcat Web Hosting services