Rendering questions
Q: What is the Rendering Process?
A Rendering is the process of taking a collection of shapes, text, and images and figuring out what colors the pixels should be on a screen or printer. In the Java 2D API, the Graphics2D class is the rendering engine: the Graphics2D object contains state attributes, such as color, and applies these attributes to the primitives when rendering them to various output devices.
The seven different attributes are:
paint, which represents the color or pattern rendered to the destination for the text and shape draw and fill methods.
stroke, which describes the line style of the outline of shapes which are rendered using the shape draw (but not fill) methods.
font, which is the font of the text to be rendered in the text draw methods.
rendering hint, which suggests optional algorithms for how a primitive should be rendered, such as whether a faster or more accurate algorithm should be used.
transform, which represents the mapping from user space to device space and additional coordinate transforms, such as rotate and scale, to be applied to all primitives.
composite, which defines how the paint colors should replace or be mixed or blended with the colors already in the destination for all primitives.
clip, which identifies a subset of the pixels in the destination which are allowed to be changed. Pixels which fall outside the clip should never be modified by any primitive.
The following figure illustrates the rendering process:

Q: What kinds of shapes can I draw using Java 2D?
A: The Java 2D API provides classes for drawing basic shapes like rectangles and circles but also allows you to draw any arbitrary shape. The following table lists the classes that represent predetermined shapes.
Arc2D Represents an arc defined by a bounding rectangle, start angle, angular extent, and a closure type.
CubicCurve2D Represents a cubic parametric curve segment.
Ellipse2D Represents an ellipse defined by a bounding rectangle.
Line2D Represents a line segment in (x, y) coordinate space.
Point2D A point representing a location in (x,y) coordinate space. Points render nothing when drawn or filled, but the Point2D class is used in many of the APIs that manipulate or construct shapes.
QuadCurve2D Represents a quadratic parametric curve segment.
Rectangle2D Represents a rectangle defined by a location (x, y) and dimension (w x h).
RoundRectangle2D Represents a rectangle with rounded corners defined by a location (x, y), a dimension (w x h), and the width and height of the corner arcs.
In addition to these classes that allow you to create common shapes, the Java 2D API provides two other classes that allow you to define odd shapes: GeneralPath and Area. Shapes created with GeneralPath must be created segment by segment, but this means that you can combine straight lines and curved lines into a single shape. The Area class supports constructive area geometry, which allows you to combine two shapes to create another shape, either by adding or intersecting the shapes, subtracting one shape from another, or by subtracting the intersection of the shapes. To see Java 2D and CAG in action, go to
Constructing Complex Shapes from Geometry Primitives in the Java Tutorial.
You can also create a Shape object from a String by calling getOutline on a TextLayout object. After creating the Shape, you can perform operations such as filling and transforming on the Shape.
For more information on working with shapes in Java 2D, see the 2D Graphics tutorial.
Q: How do I draw on an image?
A: If your image is an external image in a format such as JPG then first you load it into a BufferedImage using the javax.imageio.ImageIO class Then you can obtain a Graphics2D for rendering to the in-memory copy of the image. Here's a sample that does this:
BufferedImage bi = null;
try {
bi = ImageIO.read(new File("images/bld.jpg"));
} catch (IOException ioe) {
}
Graphics2D g2d = bi.createGraphics();
g2d.drawLine(10, 10, 20, 20); // draw a line on the image
...
g2d.dispose();
Q: I have a shape whose outline intersects itself. How do I control the filling of the shape?
A: You can control the filling of an arbitrary shape by setting the winding rule. The winding rule specifies which part of a shape is considered the inside of the shape. If you have an arbitrary shape with an outline that intersects itself, you might get different filling results depending on which winding rule you choose. Because the GeneralPath class is used to represent such arbitrary shapes, any Shape objects that are instances of GeneralPath can use the setWindingRule(int) method to set the winding rule to either WIND_NON_ZERO or WIND_EVEN_ODD. See the GeneralPath class comments for a description of each winding rule.
Note that any given Shape can only have a single winding rule that applies for its entire outline. If you have a complex combination of shapes that overlap and intersect with each other in many places, it may be easier to use the Area class to combine the shapes with explicit intersection, union, subtraction and exclusive or operations rather than to try to control the action of the multiple overlapping sections with a single winding rule.
Q: What does it mean to flatten a Shape?
A: Flattening is the process of converting the curved lines of a Shape into straight line segments. During rasterization, flattening is often performed on all curved path segments before they are stroked or filled because rendering calculations are much faster for straight lines than for curves. Shape objects provide a getPathIterator(aT, flatness) method which returns a PathIterator object that iterates through the path with only straight line segments that approximate the original path of the Shape. The flatness parameter must be a double value greater than or equal to 0.0 which controls how closely the straight lines approximate the curve. The smaller the number, the closer the straight lines will approximate the curve. The original Shape object is not modified by this method as the flattening is done on the fly as the path is iterated.
Q: How do I draw a quadratic arrow-headed curves?
A: There is no direct API for doing this. However, the following sample code can be used to achieve this effect.
...
GeneralPath path = new GeneralPath();
float p1x = 10, p1y = 10; // P1
float p2x = 100, p2y = 10; // P2
float cx = 55, cy = 50; // Control point of the curve
float arrSize = 5; // Size of the arrow segments
float adjSize = (float)(arrSize/Math.sqrt(2));
float ex = p2x - cx;
float ey = p2y - cy;
float abs_e = (float)Math.sqrt(ex*ex + ey*ey);
ex /= abs_e;
ey /= abs_e;
// Creating quad arrow
path.moveTo(p1x, p1y);
path.quadTo(cx, cy, p2x, p2y);
path.lineTo(p2x + (ey-ex)*adjSize, p2y - (ex + ey)*adjSize);
path.moveTo(p2x, p2y);
path.lineTo(p2x - (ey + ex)*adjSize, p2y + (ex - ey)*adjSize);
...
Q: Why do I get unexpected results when I use the setTransform method of Graphics2D to perform transformations?
A: Because the setTransform method is not intended for adding new coordinate transformations onto an existing transform. In fact, when you use setTransform, you are overwriting the Graphics2D object's current transform, which might be needed for other purposes, such as applying a scaling transformation to adjust for printer resolution. The setTransform method should ONLY be used to restore the Graphics2D transform to an earlier saved state after performing some temporarily transformed rendering.
To perform transformations, use these steps:
Use getTransform to get the current transform:
AffineTransform aT = g2.getTransform();Use the transform, translate, scale, shear, or rotate methods to concatenate a transform:
g2.transform(...);Perform the rendering:
g2.draw(...);Restore the original transform using setTransform:
g2.setTransform(aT);
0 comments:
Post a Comment