mirror of https://github.com/octoleo/plantuml.git
314 lines
11 KiB
Java
314 lines
11 KiB
Java
/*
|
|
* Copyright 2003-2004, Franz-Josef Elmer, All rights reserved
|
|
*
|
|
* This library is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation; either version 2.1 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details
|
|
* (http://www.gnu.org/copyleft/lesser.html).
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
package jcckit.renderer;
|
|
|
|
import java.awt.BasicStroke;
|
|
import java.awt.Color;
|
|
import java.awt.Font;
|
|
import java.awt.Graphics2D;
|
|
import java.awt.Shape;
|
|
import java.awt.geom.AffineTransform;
|
|
import java.awt.geom.Ellipse2D;
|
|
import java.awt.geom.GeneralPath;
|
|
import java.awt.geom.Point2D;
|
|
import java.awt.geom.Rectangle2D;
|
|
|
|
import jcckit.graphic.BasicGraphicalElement;
|
|
import jcckit.graphic.ClippingRectangle;
|
|
import jcckit.graphic.ClippingShape;
|
|
import jcckit.graphic.FillAttributes;
|
|
import jcckit.graphic.FontStyle;
|
|
import jcckit.graphic.GraphPoint;
|
|
import jcckit.graphic.GraphicAttributes;
|
|
import jcckit.graphic.GraphicalComposite;
|
|
import jcckit.graphic.GraphicalCompositeRenderer;
|
|
import jcckit.graphic.LineAttributes;
|
|
import jcckit.graphic.Oval;
|
|
import jcckit.graphic.OvalRenderer;
|
|
import jcckit.graphic.Polygon;
|
|
import jcckit.graphic.PolygonRenderer;
|
|
import jcckit.graphic.Rectangle;
|
|
import jcckit.graphic.RectangleRenderer;
|
|
import jcckit.graphic.Text;
|
|
import jcckit.graphic.TextAttributes;
|
|
import jcckit.graphic.TextRenderer;
|
|
|
|
/**
|
|
* Renderer who draws the {@link jcckit.graphic.GraphicalElement
|
|
* GraphicalElements} into a <tt>java.awt.Graphics2D</tt> context.
|
|
* <p>
|
|
* The default color for lines and texts is determined by the current color of
|
|
* the <tt>Graphics2D</tt> context when a new instance of
|
|
* <tt>Graphics2DRenderer</tt> is created.
|
|
* <p>
|
|
* The default font is <tt>SansSerif-12</tt>.
|
|
*
|
|
* @author Franz-Josef Elmer
|
|
*/
|
|
public class Graphics2DRenderer implements GraphicalCompositeRenderer, PolygonRenderer, OvalRenderer, TextRenderer,
|
|
RectangleRenderer {
|
|
private static final int FS = 1;
|
|
private static final String DEFAULT_FONT_NAME = "SansSerif";
|
|
private static final FontStyle DEFAULT_FONT_STYLE = FontStyle.NORMAL;
|
|
private static final int DEFAULT_FONT_SIZE = 12;
|
|
|
|
private Color _defaultColor;
|
|
private Graphics2D _graphics;
|
|
|
|
/**
|
|
* Initializes this instance. During renderering the current transformation
|
|
* will be leaved unchanged. But the current Clip may be cleared.
|
|
*
|
|
* @param graphics
|
|
* Graphics2D context into which the
|
|
* {@link BasicGraphicalElement BaiscGraphicalElements} are
|
|
* painted.
|
|
* @return this instance.
|
|
*/
|
|
public Graphics2DRenderer init(Graphics2D graphics) {
|
|
_graphics = graphics;
|
|
_defaultColor = graphics.getColor(); // the foreground color
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Starts rendering of the specified composite. Does nothing except if
|
|
* <tt>composite</tt> has a {@link ClippingShape}. In this case the Clip
|
|
* of the <tt>Graphics2D</tt> context becomes the clipping rectangle
|
|
* determined by the bounding box of the <tt>ClippingShape</tt>.
|
|
*/
|
|
public void startRendering(GraphicalComposite composite) {
|
|
ClippingShape shape = composite.getClippingShape();
|
|
if (shape != null) {
|
|
ClippingRectangle rect = shape.getBoundingBox();
|
|
_graphics.clip(new Rectangle2D.Double(rect.getMinX(), rect.getMinY(), rect.getMaxX() - rect.getMinX(), rect
|
|
.getMaxY()
|
|
- rect.getMinY()));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Finishes rendering of the specified composite. Does nothing except if
|
|
* <tt>composite</tt> has a {@link ClippingShape}. In this case the Clip
|
|
* of the <tt>Graphics2D</tt> context will be cleared.
|
|
*/
|
|
public void finishRendering(GraphicalComposite composite) {
|
|
_graphics.setClip(null);
|
|
}
|
|
|
|
/** Paints the specified polygon into the <tt>Graphics2D</tt> context. */
|
|
public void render(Polygon polygon) {
|
|
int numberOfPoints = polygon.getNumberOfPoints();
|
|
if (numberOfPoints > 0) {
|
|
Color currentColor = _graphics.getColor();
|
|
GeneralPath p = new GeneralPath(GeneralPath.WIND_EVEN_ODD, numberOfPoints);
|
|
p.moveTo((float) polygon.getPoint(0).getX(), (float) polygon.getPoint(0).getY());
|
|
for (int i = 1; i < numberOfPoints; i++) {
|
|
p.lineTo((float) polygon.getPoint(i).getX(), (float) polygon.getPoint(i).getY());
|
|
}
|
|
if (polygon.isClosed()) {
|
|
p.closePath();
|
|
}
|
|
drawShape(p, polygon, currentColor);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Paints the specified rectangle into the current <tt>Graphics</tt>
|
|
* context.
|
|
*/
|
|
public void render(Rectangle rectangle) {
|
|
Color currentColor = _graphics.getColor();
|
|
GraphPoint center = rectangle.getCenter();
|
|
double width = rectangle.getWidth();
|
|
double height = rectangle.getHeight();
|
|
Rectangle2D rect = new Rectangle2D.Double(center.getX() - 0.5 * width, center.getY() - 0.5 * height, width,
|
|
height);
|
|
drawShape(rect, rectangle, currentColor);
|
|
}
|
|
|
|
/**
|
|
* Paints the specified oval into the current <tt>Graphics</tt> context.
|
|
*/
|
|
public void render(Oval oval) {
|
|
Color currentColor = _graphics.getColor();
|
|
GraphPoint center = oval.getCenter();
|
|
double width = oval.getWidth();
|
|
double height = oval.getHeight();
|
|
Ellipse2D ellipse = new Ellipse2D.Double(center.getX() - 0.5 * width, center.getY() - 0.5 * height, width,
|
|
height);
|
|
drawShape(ellipse, oval, currentColor);
|
|
}
|
|
|
|
private void drawShape(Shape shape, BasicGraphicalElement element, Color backupColor) {
|
|
GraphicAttributes attributes = element.getGraphicAttributes();
|
|
Color fillColor = null;
|
|
if (element.isClosed() && attributes instanceof FillAttributes) {
|
|
fillColor = ((FillAttributes) attributes).getFillColor();
|
|
}
|
|
if (fillColor != null) {
|
|
_graphics.setColor(fillColor);
|
|
_graphics.fill(shape);
|
|
}
|
|
Color lineColor = _defaultColor;
|
|
if (attributes instanceof LineAttributes) {
|
|
LineAttributes la = (LineAttributes) attributes;
|
|
BasicStroke stroke = new BasicStroke((float) la.getLineThickness());
|
|
double[] linePattern = la.getLinePattern();
|
|
if (linePattern != null) {
|
|
float[] dash = new float[linePattern.length];
|
|
for (int i = 0; i < dash.length; i++) {
|
|
dash[i] = (float) la.getLinePattern()[i];
|
|
}
|
|
stroke = new BasicStroke(stroke.getLineWidth(), BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f,
|
|
dash, 0f);
|
|
}
|
|
_graphics.setStroke(stroke);
|
|
if (la.getLineColor() != null || fillColor != null) {
|
|
lineColor = la.getLineColor();
|
|
}
|
|
}
|
|
if (lineColor != null) {
|
|
_graphics.setColor(lineColor);
|
|
_graphics.draw(shape);
|
|
}
|
|
_graphics.setColor(backupColor);
|
|
}
|
|
|
|
/**
|
|
* Paints the specified text into the current <tt>Graphics</tt> context.
|
|
* <p>
|
|
* If the font size is zero the default font size will be used.
|
|
* <p>
|
|
* If the orientation angle is unequal zero the text will first be painted
|
|
* into an off-screen image and rotated. Finally, it will be drawn into the
|
|
* current <tt>Graphics</tt> context. Note, that only integer multiples of
|
|
* 90 degree rotation are performed. Other orientation angles will be
|
|
* adjusted to the nearest integer multiple of 90 degree.
|
|
*/
|
|
public void render(Text text) {
|
|
final GraphicAttributes ga = text.getGraphicAttributes();
|
|
if (ga instanceof TextAttributes) {
|
|
final TextAttributes ta = (TextAttributes) ga;
|
|
final Color currentColor = _graphics.getColor();
|
|
Color fontColor = ta.getTextColor();
|
|
if (fontColor == null) {
|
|
fontColor = _defaultColor;
|
|
}
|
|
_graphics.setColor(fontColor);
|
|
|
|
final double scale = _graphics.getTransform().getScaleX();
|
|
final String str = text.getText();
|
|
|
|
AffineTransform before = _graphics.getTransform();
|
|
_graphics.setTransform(new AffineTransform());
|
|
|
|
double fs = ta.getFontSize();
|
|
fs = fs == 0 ? 1 : fs * scale / DEFAULT_FONT_SIZE;
|
|
|
|
Font font = createFont(ta, 0);
|
|
|
|
AffineTransform fontTransform = new AffineTransform();
|
|
fontTransform.scale(fs, fs);
|
|
fontTransform.rotate(-ta.getOrientationAngle() * Math.PI / 180);
|
|
font = font.deriveFont(fontTransform);
|
|
_graphics.setFont(font);
|
|
Rectangle2D bounds = _graphics.getFontMetrics().getStringBounds(str, _graphics);
|
|
|
|
fontTransform.rotate(-ta.getOrientationAngle() * Math.PI / 180);
|
|
|
|
final double yy = bounds.getHeight() + bounds.getY();
|
|
|
|
Point2D.Double pos = new Point2D.Double(text.getPosition().getX(), text.getPosition().getY());
|
|
before.transform(pos, pos);
|
|
|
|
double x = 0;
|
|
double y = 0;
|
|
if (ta.getOrientationAngle() == 0) {
|
|
x = -0.5 * ta.getHorizontalAnchor().getFactor() * bounds.getWidth();
|
|
y = 0.5 * ta.getVerticalAnchor().getFactor() * bounds.getHeight() - yy;
|
|
x = pos.x + x;
|
|
y = pos.y + y;
|
|
} else {
|
|
x = 0.5 * ta.getVerticalAnchor().getFactor() * bounds.getHeight();
|
|
y = 0.5 * ta.getHorizontalAnchor().getFactor() * bounds.getWidth();
|
|
// System.err.println("yy="+y+" dx="+x+" dy="+y);
|
|
// x = 0;
|
|
// y = 0;
|
|
x = pos.x + x;
|
|
y = pos.y + y;
|
|
}
|
|
|
|
// if (ta.getOrientationAngle() == 0) {
|
|
//// System.err.println("x0=" + x);
|
|
//// System.err.println("y0=" + y);
|
|
// } else {
|
|
// System.err.println("bounds=" + bounds + " y=" + bounds.getY() + " h=" + bounds.getHeight() + " vert="
|
|
// + ta.getVerticalAnchor().getFactor()+" horz="+ta.getHorizontalAnchor().getFactor());
|
|
// System.err.println("x1=" + x);
|
|
// System.err.println("y1=" + y);
|
|
// }
|
|
|
|
|
|
_graphics.drawString(str, (float) x, (float) y);
|
|
// _graphics.fillRect((int)x, (int)y, 5, 5);
|
|
_graphics.setTransform(before);
|
|
_graphics.setColor(currentColor);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates a font instance based on the specified text attributes and font
|
|
* size.
|
|
*
|
|
* @param attributes
|
|
* Text attributes (font name and style).
|
|
* @param size
|
|
* Font size in pixel. If 0 {@link #DEFAULT_FONT_SIZE} will be
|
|
* used.
|
|
* @return new font instance.
|
|
*/
|
|
static Font createFont(TextAttributes attributes, int size) {
|
|
String fontName = attributes.getFontName();
|
|
if (fontName == null) {
|
|
fontName = DEFAULT_FONT_NAME;
|
|
}
|
|
|
|
FontStyle fontStyle = attributes.getFontStyle();
|
|
if (fontStyle == null) {
|
|
fontStyle = DEFAULT_FONT_STYLE;
|
|
}
|
|
int style = Font.PLAIN;
|
|
if (fontStyle == FontStyle.BOLD) {
|
|
style = Font.BOLD;
|
|
} else if (fontStyle == FontStyle.ITALIC) {
|
|
style = Font.ITALIC;
|
|
} else if (fontStyle == FontStyle.BOLD_ITALIC) {
|
|
style = Font.BOLD + Font.ITALIC;
|
|
}
|
|
|
|
if (size == 0) {
|
|
size = DEFAULT_FONT_SIZE;
|
|
}
|
|
|
|
return new Font(fontName, style, size);
|
|
}
|
|
|
|
}
|