490 lines
14 KiB
Java
490 lines
14 KiB
Java
/*
|
|
|
|
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
|
|
|
|
This file is part of C.a.R. software.
|
|
|
|
C.a.R. is a free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, version 3 of the License.
|
|
|
|
C.a.R. 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
package rene.zirkel.graphics;
|
|
|
|
/* Graphics class supporting EPS export from plots.
|
|
|
|
Copyright (c) 1998-2000 The Regents of the University of
|
|
California.
|
|
|
|
Modified, completed and extended by R. Grothmann
|
|
|
|
*/
|
|
|
|
import java.awt.Color;
|
|
import java.awt.Font;
|
|
import java.awt.FontMetrics;
|
|
import java.awt.Rectangle;
|
|
import java.awt.Shape;
|
|
import java.io.IOException;
|
|
import java.io.OutputStream;
|
|
import java.io.PrintWriter;
|
|
|
|
class EpsFontMetrics extends FontMetrics {
|
|
/**
|
|
*
|
|
*/
|
|
private static final long serialVersionUID = 1L;
|
|
Font F;
|
|
|
|
public EpsFontMetrics(final Font f) {
|
|
super(f); // a dummy font.
|
|
F = f;
|
|
}
|
|
|
|
@Override
|
|
public int stringWidth(final String s) {
|
|
return s.length() * F.getSize() / 2;
|
|
}
|
|
|
|
@Override
|
|
public int getHeight() {
|
|
return F.getSize();
|
|
}
|
|
|
|
@Override
|
|
public int getAscent() {
|
|
return F.getSize() * 4 / 5;
|
|
}
|
|
|
|
}
|
|
|
|
class EpsPoint {
|
|
double x, y;
|
|
|
|
public EpsPoint(final double xx, final double yy) {
|
|
x = xx;
|
|
y = yy;
|
|
}
|
|
}
|
|
|
|
public class EPSGraphics {
|
|
|
|
// ///////////////////////////////////////////////////////////////
|
|
//
|
|
// // private variables
|
|
// //
|
|
|
|
private Color _currentColor = Color.black;
|
|
private Font _currentFont;
|
|
private final double _height;
|
|
int _orientation;
|
|
private final OutputStream _out;
|
|
private final StringBuffer _buffer = new StringBuffer();
|
|
private double LineWidth = 1;
|
|
|
|
public static final int PORTRAIT = 0;
|
|
public static final int LANDSCAPE = 1;
|
|
|
|
private FontMetrics FM;
|
|
|
|
public EPSGraphics(final OutputStream out, final double width,
|
|
final double height, final int orientation, final boolean clip) {
|
|
_height = height;
|
|
_orientation = orientation;
|
|
_out = out;
|
|
_buffer.append("%!PS-Adobe-3.0 EPSF-3.0\n");
|
|
_buffer.append("%%Creator: QCircuitBuilder\n");
|
|
_buffer.append("%%BoundingBox: 50 50 " + (int) (50 + width) + " "
|
|
+ (int) (50 + height) + "\n");
|
|
// _buffer.append("%%Orientation: " + (_orientation == PORTRAIT ?
|
|
// "Portrait" : "Landscape"));
|
|
// _buffer.append("%%PageOrientation: " + (_orientation == PORTRAIT ?
|
|
// "Portrait" : "Landscape"));
|
|
_buffer.append("%%Pages: 1\n");
|
|
_buffer.append("%%Page: 1 1\n");
|
|
_buffer.append("%%LanguageLevel: 2\n");
|
|
if (clip)
|
|
clipRect(0, 0, width, height);
|
|
_buffer.append("/Helvetica findfont 10 scalefont setfont\n");
|
|
}
|
|
|
|
public void clearRect(final int x, final int y, final int width,
|
|
final int height) {
|
|
}
|
|
|
|
// Clip
|
|
public void clipRect(final double x, final double y, final double width,
|
|
final double height) {
|
|
final EpsPoint start = _convert(x, y);
|
|
// _fillPattern();
|
|
_buffer.append("newpath " + round(start.x) + " " + round(start.y)
|
|
+ " moveto\n");
|
|
_buffer.append("0 " + round(-height) + " rlineto\n");
|
|
_buffer.append("" + round(width) + " 0 rlineto\n");
|
|
_buffer.append("0 " + round(height) + " rlineto\n");
|
|
_buffer.append("" + round(-width) + " 0 rlineto\n");
|
|
_buffer.append("closepath clip\n");
|
|
}
|
|
|
|
private double round(final double x) {
|
|
return Math.round(x * 1000.0) / 1000.0;
|
|
}
|
|
|
|
/**
|
|
* Draw a line, using the current color, between the points (x1, y1) and
|
|
* (x2, y2) in this graphics context's coordinate system.
|
|
*
|
|
* @param x1
|
|
* the x coordinate of the first point.
|
|
* @param y1
|
|
* the y coordinate of the first point.
|
|
* @param x2
|
|
* the x coordinate of the second point.
|
|
* @param y2
|
|
* the y coordinate of the second point.
|
|
*/
|
|
public void drawLine(final double x1, final double y1, final double x2,
|
|
final double y2) {
|
|
final EpsPoint start = _convert(x1, y1);
|
|
final EpsPoint end = _convert(x2, y2);
|
|
_buffer.append("newpath " + round(start.x) + " " + round(start.y)
|
|
+ " moveto\n");
|
|
_buffer.append("" + round(end.x) + " " + round(end.y) + " lineto\n");
|
|
_buffer.append("stroke\n");
|
|
}
|
|
|
|
/**
|
|
* Draw a closed polygon defined by arrays of x and y coordinates. Each pair
|
|
* of (x, y) coordinates defines a vertex. The third argument gives the
|
|
* number of vertices. If the arrays are not long enough to define this many
|
|
* vertices, or if the third argument is less than three, then nothing is
|
|
* drawn.
|
|
*
|
|
* @param xPoints
|
|
* An array of x coordinates.
|
|
* @param yPoints
|
|
* An array of y coordinates.
|
|
* @param nPoints
|
|
* The total number of vertices.
|
|
*/
|
|
public void drawPolygon(final double xPoints[], final double yPoints[],
|
|
final int nPoints) {
|
|
if (!_polygon(xPoints, yPoints, nPoints)) {
|
|
return;
|
|
} else {
|
|
_buffer.append("closepath stroke\n");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Draw an oval bounded by the specified rectangle with the current color.
|
|
*
|
|
* @param x
|
|
* The x coordinate of the upper left corner
|
|
* @param y
|
|
* The y coordinate of the upper left corner
|
|
* @param width
|
|
* The width of the oval to be filled.
|
|
* @param height
|
|
* The height of the oval to be filled.
|
|
*/
|
|
// FIXME: Currently, this ignores the fourth argument and
|
|
// draws a circle with diameter given by the third argument.
|
|
public void drawOval(final double x, final double y, final double width,
|
|
final double height) {
|
|
final double radius = width / 2.0;
|
|
_buffer.append("newpath " + _convertX(x + radius) + " "
|
|
+ _convertY(y + radius) + " " + round(radius)
|
|
+ " 0 360 arc closepath stroke\n");
|
|
}
|
|
|
|
public void drawRect(final double x, final double y, final double width,
|
|
final double height) {
|
|
final EpsPoint start = _convert(x, y);
|
|
_buffer.append("newpath " + round(start.x) + " " + round(start.y)
|
|
+ " moveto\n");
|
|
_buffer.append("0 " + round(-height) + " rlineto\n");
|
|
_buffer.append("" + round(width) + " 0 rlineto\n");
|
|
_buffer.append("0 " + round(height) + " rlineto\n");
|
|
_buffer.append("" + round(-width) + " 0 rlineto\n");
|
|
_buffer.append("closepath stroke\n");
|
|
}
|
|
|
|
public void drawRoundRect(final double x, final double y,
|
|
final double width, final double height, final int arcWidth,
|
|
final int arcHeight) {
|
|
}
|
|
|
|
public void drawString(
|
|
final java.text.AttributedCharacterIterator iterator, final int x,
|
|
final int y) {
|
|
}
|
|
|
|
public void drawString(final String str, final double x, final double y) {
|
|
getFontMetrics();
|
|
final EpsPoint start = _convert(x, y);
|
|
_buffer.append("" + start.x + " " + start.y + " moveto\n");
|
|
_buffer.append("(" + str + ") show\n");
|
|
}
|
|
|
|
public void drawArc(final double x, final double y, final double width,
|
|
final double height, final double startAngle, final double arcAngle) {
|
|
final double radius = width / 2.0;
|
|
_buffer.append("newpath " + _convertX(x + radius) + " "
|
|
+ _convertY(y + radius) + " " + round(radius) + " "
|
|
+ round(startAngle) + " " + " " + round(startAngle + arcAngle)
|
|
+ " arc stroke\n");
|
|
}
|
|
|
|
public void fillArc(final double x, final double y, final double width,
|
|
final double height, final double startAngle, final double arcAngle) {
|
|
final double radius = width / 2.0;
|
|
_buffer.append("newpath " + _convertX(x + radius) + " "
|
|
+ _convertY(y + radius) + " " + " moveto "
|
|
+ _convertX(x + radius) + " " + _convertY(y + radius) + " "
|
|
+ radius + " " + round(startAngle) + " "
|
|
+ round(startAngle + arcAngle) + " arc closepath fill\n");
|
|
}
|
|
|
|
public void fillChord(final double x, final double y, final double width,
|
|
final double height, final double startAngle, final double arcAngle) {
|
|
final double radius = width / 2.0;
|
|
_buffer.append("newpath " + _convertX(x + radius) + " "
|
|
+ _convertY(y + radius) + " " + round(radius) + " "
|
|
+ round(startAngle) + " " + round(startAngle + arcAngle)
|
|
+ " arc fill\n");
|
|
}
|
|
|
|
public void fillPolygon(final double xPoints[], final double yPoints[],
|
|
final int nPoints) {
|
|
if (!_polygon(xPoints, yPoints, nPoints)) {
|
|
return;
|
|
} else {
|
|
_buffer.append("closepath fill\n");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fill an oval bounded by the specified rectangle with the current color.
|
|
*
|
|
* @param x
|
|
* The x coordinate of the upper left corner
|
|
* @param y
|
|
* The y coordinate of the upper left corner
|
|
* @param width
|
|
* The width of the oval to be filled.
|
|
* @param height
|
|
* The height of the oval to be filled.
|
|
*/
|
|
// FIXME: Currently, this ignores the fourth argument and draws a circle
|
|
// with diameter given by the third argument.
|
|
public void fillOval(final double x, final double y, final double width,
|
|
final double height) {
|
|
final double radius = width / 2.0;
|
|
_buffer.append("newpath " + _convertX(x + radius) + " "
|
|
+ _convertY(y + radius) + " " + radius
|
|
+ " 0 360 arc closepath fill\n");
|
|
}
|
|
|
|
/**
|
|
* Fill the specified rectangle and draw a thin outline around it. The left
|
|
* and right edges of the rectangle are at x and x + width - 1. The top and
|
|
* bottom edges are at y and y + height - 1. The resulting rectangle covers
|
|
* an area width pixels wide by height pixels tall. The rectangle is filled
|
|
* using the brightness of the current color to set the level of gray.
|
|
*
|
|
* @param x
|
|
* The x coordinate of the top left corner.
|
|
* @param y
|
|
* The y coordinate of the top left corner.
|
|
* @param width
|
|
* The width of the rectangle.
|
|
* @param height
|
|
* The height of the rectangle.
|
|
*/
|
|
public void fillRect(final double x, final double y, final double width,
|
|
final double height) {
|
|
final EpsPoint start = _convert(x, y);
|
|
// _fillPattern();
|
|
_buffer.append("newpath " + start.x + " " + start.y + " moveto\n");
|
|
_buffer.append("0 " + round(-height) + " rlineto\n");
|
|
_buffer.append("" + round(width) + " 0 rlineto\n");
|
|
_buffer.append("0 " + round(height) + " rlineto\n");
|
|
_buffer.append("" + round(-width) + " 0 rlineto\n");
|
|
_buffer.append("closepath gsave fill grestore\n");
|
|
_buffer.append("0.5 setlinewidth 0 setgray [] 0 setdash stroke\n");
|
|
// reset the gray scale to black
|
|
_buffer.append(round(LineWidth) + " setlinewidth\n");
|
|
}
|
|
|
|
public void fillRoundRect(final double x, final double y,
|
|
final double width, final double height, final int arcWidth,
|
|
final int arcHeight) {
|
|
}
|
|
|
|
public Shape getClip() {
|
|
return null;
|
|
}
|
|
|
|
public Rectangle getClipBounds() {
|
|
return null;
|
|
}
|
|
|
|
public Color getColor() {
|
|
return _currentColor;
|
|
}
|
|
|
|
public Font getFont() {
|
|
return _currentFont;
|
|
}
|
|
|
|
public FontMetrics getFontMetrics(final Font f) {
|
|
if (FM == null)
|
|
FM = new EpsFontMetrics(new Font("dialog", Font.PLAIN, 20));
|
|
return FM;
|
|
}
|
|
|
|
public FontMetrics getFontMetrics() {
|
|
return getFontMetrics(_currentFont);
|
|
}
|
|
|
|
public void setFont(final Font font) {
|
|
final int size = font.getSize();
|
|
final boolean bold = font.isBold();
|
|
if (bold) {
|
|
_buffer.append("/Helvetica-Bold findfont\n");
|
|
} else {
|
|
_buffer.append("/Helvetica findfont\n");
|
|
}
|
|
_buffer.append("" + size + " scalefont setfont\n");
|
|
_currentFont = font;
|
|
FM = new EpsFontMetrics(font);
|
|
}
|
|
|
|
public void setClip(final Shape clip) {
|
|
}
|
|
|
|
public void setClip(final int x, final int y, final int width,
|
|
final int height) {
|
|
}
|
|
|
|
/**
|
|
* Set the current color.
|
|
*
|
|
* @param c
|
|
* The desired current color.
|
|
*/
|
|
public void setColor(final Color c) {
|
|
_buffer.append(c.getRed() / 255.0);
|
|
_buffer.append(" ");
|
|
_buffer.append(c.getGreen() / 255.0);
|
|
|
|
_buffer.append(" ");
|
|
_buffer.append(c.getBlue() / 255.0);
|
|
|
|
_buffer.append(" setrgbcolor\n");
|
|
// _buffer.append("[] 0 setdash\n");
|
|
// _buffer.append("1 setlinewidth\n");
|
|
|
|
_currentColor = c;
|
|
}
|
|
|
|
public void setLineWidth(final double w) {
|
|
_buffer.append(round(w) + " setlinewidth\n");
|
|
LineWidth = w;
|
|
}
|
|
|
|
public void setDash(final double a, final double b) {
|
|
_buffer.append("[" + round(a) + " " + round(b) + " ] 0 setdash\n");
|
|
}
|
|
|
|
public void clearDash() {
|
|
_buffer.append("[ ] 0 setdash\n");
|
|
}
|
|
|
|
public void setPaintMode() {
|
|
}
|
|
|
|
public void setXORMode(final Color c1) {
|
|
}
|
|
|
|
/**
|
|
* Issue the PostScript showpage command, then write and flush the output.
|
|
*/
|
|
public void showpage(final String name) {
|
|
try {
|
|
// _buffer.append("showpage\n");
|
|
_buffer.append("%%EOF");
|
|
|
|
final PrintWriter output = new PrintWriter(new java.io.FileWriter(
|
|
name));
|
|
|
|
output.println(_buffer.toString());
|
|
output.flush();
|
|
|
|
} catch (final Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Issue the PostScript showpage command, then write and flush the output.
|
|
*/
|
|
public void close() throws IOException {
|
|
_buffer.append("showpage\n");
|
|
_buffer.append("%%EOF");
|
|
|
|
final PrintWriter output = new PrintWriter(_out);
|
|
|
|
output.println(_buffer.toString());
|
|
output.flush();
|
|
|
|
}
|
|
|
|
// ///////////////////////////////////////////////////////////////
|
|
//
|
|
// // private methods
|
|
// //
|
|
|
|
// Convert the screen coordinate system to that of postscript.
|
|
private EpsPoint _convert(final double x, final double y) {
|
|
return new EpsPoint(round(x + 50), round(_height + 50 - y));
|
|
}
|
|
|
|
private double _convertX(final double x) {
|
|
return round(x + 50);
|
|
}
|
|
|
|
private double _convertY(final double y) {
|
|
return round(_height + 50 - y);
|
|
}
|
|
|
|
// Draw a closed polygon defined by arrays of x and y coordinates.
|
|
// Return false if arguments are misformed.
|
|
private boolean _polygon(final double xPoints[], final double yPoints[],
|
|
final int nPoints) {
|
|
if (nPoints < 3 || xPoints.length < nPoints || yPoints.length < nPoints)
|
|
return false;
|
|
final EpsPoint start = _convert(xPoints[0], yPoints[0]);
|
|
_buffer.append("newpath " + round(start.x) + " " + round(start.y)
|
|
+ " moveto\n");
|
|
for (int i = 1; i < nPoints; i++) {
|
|
final EpsPoint vertex = _convert(xPoints[i], yPoints[i]);
|
|
_buffer.append("" + round(vertex.x) + " " + round(vertex.y)
|
|
+ " lineto\n");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
}
|