⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 psg.java

📁 java高级使用教程 全书一共分六章
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
// Psg - a PostScript-like alternative to the Graphics class
//
// Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>.  All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
// Visit the ACME Labs Java page for up-to-date versions of this and other
// fine Java utilities: http://www.acme.com/java/

package Acme;

import java.util.*;
import java.awt.*;
import java.awt.image.*;
import java.applet.*;

/// <A HREF="http://java.developer.com/"><IMG WIDTH=162 HEIGHT=35 ALIGN="right" SRC="/resources/gamelan_best.jpg"></A>
// <A HREF="http://www.developer.com/whatscool/"><IMG WIDTH=173 HEIGHT=36 ALIGN="right" SRC="/resources/gamelan_cool.png"></A>
// A PostScript-like alternative to the Graphics class.
// <P>
// This class provides a functional equivalent of java.awt.Graphics,
// but with a very PostScript-like interface.  It implements the following
// PostScript operators:
// <BLOCKQUOTE>
// gsave grestore grestoreall initgraphics setlinewidth setcolor setgray
// sethsbcolor setrgbcolor translate scale rotate transform dtransform
//  itransform idtransform
// newpath moveto rmoveto lineto rlineto arc arcn curveto rcurveto closepath
//  flattenpath clippath pathbbox
// erasepage fill stroke
//  rectfill rectstroke
//  findfont scalefont setfont
// show stringwidth
// </BLOCKQUOTE>
// Not only is this a more powerful rendering idiom than the standard
// Graphics class, but it also makes it hellof easy to translate
// PostScript graphics hacks into Java.  Here's a
// <A HREF="/resources/classes/Yoyo.java">sample</A>:
// <BLOCKQUOTE>
// <APPLET WIDTH=300 HEIGHT=200 CODEBASE="/resources/classes" CODE="Yoyo">
// </APPLET>
// </BLOCKQUOTE>
// <P>
// JavaSoft and Adobe are said to be working on a 2-D rendering API
// similar to PostScript, and therefore similar to this.  When that
// comes out this class will probably be obsolete, so I don't plan
// on doing any major improvements.
// <P>
// <A HREF="/resources/classes/Acme/Psg.java">Fetch the software.</A><BR>
// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>

public class Psg
    {

    private Component component;
    private Graphics graphics;
    private PsgState current;
    private Stack gStack;
    private Vector path;		// holds PsgPathItems
    private PsgPathItem subpathStart;	// pointer to most recent move

    /// Constructor from Component.
    // This is the preferred way to make a Psg.
    public Psg( Component component )
	{
	this.component = component;
	this.graphics = component.getGraphics();
	initgraphics();
	}

    /// Constructor from Graphics.
    // If you don't have a Component, you can create a Psg from a Graphics
    // instead, but this is not as good.
    public Psg( Graphics graphics )
	{
	this.component = null;
	this.graphics = graphics;
	initgraphics();
	}

    /// Save the current graphics state onto a stack.
    public void gsave()
	{
	PsgState next = (PsgState) current.clone();
	gStack.push( current );
	current = next;
	}

    /// Restore the last Save()ed graphics state.
    public void grestore()
	{
	if ( gStack.empty() )
	    initgraphics();
	else
	    {
	    current = (PsgState) gStack.pop();
	    if ( current.font == null )
		graphics.setFont( current.font );
	    }
	}

    /// Pop to bottom-most graphics state.
    public void grestoreall()
	{
	// This is equivalent to initgraphics(), isn't it?
	while ( ! gStack.empty() )
	    grestore();
	}

    /// Reset graphics state.
    public void initgraphics()
	{
	current = new PsgState();
	gStack = new Stack();
	path = new Vector();
	subpathStart = null;
	// Set the current transformation to fit screen space.
	Dimension d = size();
	this.translate( 0.0, d.height );
	this.scale( 1.0, -1.0 );
	erasepage();
	}

    /// Set the current line width.
    public void setlinewidth( double linewidth )
	{
	current.linewidth = wtransform( linewidth );
	}

    /// Set the current color.
    public void setcolor( Color color )
	{
	current.color = color;
	}

    /// Set the color to the specified gray value (0=black, 1=white).
    public void setgray( float grayVal )
	{
	setrgbcolor( grayVal, grayVal, grayVal );
	}

    /// Set the color from HSB coordinates.
    public void sethsbcolor( float hue, float saturation, float brightness )
	{
	setcolor( new Color( Color.HSBtoRGB( hue, saturation, brightness ) ) );
	}

    /// Set the color from RGB coordinates.
    public void setrgbcolor( float r, float g, float b )
	{
	setcolor( new Color( r, g, b ) );
	}

    /// Translate graphics space.
    public void translate( double tx, double ty )
	{
	double nx =
	    tx * current.matrix.xx +
	    ty * current.matrix.yx +
	    current.matrix.tx;
	double ny =
	    ty * current.matrix.yy +
	    tx * current.matrix.xy +
	    current.matrix.ty;
	current.matrix.tx = nx;
	current.matrix.ty = ny;
	}

    /// Scale graphics space.
    public void scale( double sx, double sy )
	{
	current.matrix.xx *= sx;
	current.matrix.xy *= sx;
	current.matrix.yx *= sy;
	current.matrix.yy *= sy;
	}

    /// Rotate graphics space.
    public void rotate( double degrees )
	{
	double radians = toRadians( degrees );
	double cos = Math.cos( radians );
	double sin = Math.sin( radians );
	double sxx = current.matrix.xx;
	double sxy = current.matrix.xy;
	current.matrix.xx = cos * sxx + sin * current.matrix.yx;
	current.matrix.xy = cos * sxy + sin * current.matrix.yy;
	current.matrix.yx = cos * current.matrix.yx - sin * sxx;
	current.matrix.yy = cos * current.matrix.yy - sin * sxy;
	}

    /// Transform (x, y) into a device-space x-coordinate.
    public int transform_x( double x, double y )
	{
	return (int) (
	    x * current.matrix.xx + y * current.matrix.yx + current.matrix.tx );
	}

    /// Transform (x, y) into a device-space y-coordinate.
    public int transform_y( double x, double y )
	{
	return (int) (
	    y * current.matrix.yy + x * current.matrix.xy + current.matrix.ty );
	}

    /// Transform (dx, dy) into a device-space x-distance.
    public int dtransform_x( double dx, double dy )
	{
	return (int) ( dx * current.matrix.xx + dy * current.matrix.yx );
	}

    /// Transform (dx, dy) into a device-space y-distance.
    public int dtransform_y( double dx, double dy )
	{
	return (int) ( dy * current.matrix.yy + dx * current.matrix.xy );
	}

    /// Inverse transform (x, y) into a user-space x-coordinate.
    // @exception Acme.PsgException "undefined result"
    public double itransform_x( int x, int y ) throws PsgException
	{
	PsgMatrix inv = current.matrix.invert();
	return x * inv.xx + y * inv.yx + inv.tx;
	}

    /// Inverse transform (x, y) into a user-space y-coordinate.
    // @exception Acme.PsgException "undefined result"
    public double itransform_y( int x, int y ) throws PsgException
	{
	PsgMatrix inv = current.matrix.invert();
	return y * inv.yy + x * inv.xy + inv.ty;
	}

    /// Inverse transform (dx, dy) into a user-space x-distance.
    // @exception Acme.PsgException "undefined result"
    public double idtransform_x( int dx, int dy ) throws PsgException
	{
	PsgMatrix inv = current.matrix.invert();
	return dx * inv.xx + dy * inv.yx;
	}

    /// Inverse transform (dx, dy) into a user-space y-distance.
    // @exception Acme.PsgException "undefined result"
    public double idtransform_y( int dx, int dy ) throws PsgException
	{
	PsgMatrix inv = current.matrix.invert();
	return dy * inv.yy + dx * inv.xy;
	}

    // Transform a width into device space.
    private int wtransform( double width )
	{
	int dx = dtransform_x( width, width );
	int dy = dtransform_y( width, width );
	return ( Math.abs( dx ) + Math.abs( dy ) ) / 2;
	}

    /// Start a new, empty path.
    public void newpath()
	{
	current.point = null;
	path.setSize( 0 );
	subpathStart = null;
	}

    /// Set the current point.
    public void moveto( double x, double y )
	{
	if ( current.point == null )
	    current.point = new DoublePoint();
	current.point.x = x;
	current.point.y = y;
	PsgPathItem n =
	    new PsgPathItem(
	        transform_x( x, y ), transform_y( x, y ), 0, false );
	path.addElement( n );
	subpathStart = n;
	}

    /// Relative moveto().
    // @exception Acme.PsgException "no current point"
    public void rmoveto( double dx, double dy ) throws PsgException
	{
	if ( current.point == null )
	    throw new PsgException( "no current point" );
	moveto( current.point.x + dx, current.point.y + dy );
	}

    /// Add a line to the path.
    // @exception Acme.PsgException "no current point"
    public void lineto( double x, double y ) throws PsgException
	{
	if ( current.point == null )
	    throw new PsgException( "no current point" );
	current.point.x = x;
	current.point.y = y;
	PsgPathItem n =
	    new PsgPathItem(
		transform_x( x, y ), transform_y( x, y ),
		current.linewidth, true );
	path.addElement( n );
	}

    /// Relative lineto().
    // @exception Acme.PsgException "no current point"
    public void rlineto( double dx, double dy ) throws PsgException
	{
	if ( current.point == null )
	    throw new PsgException( "no current point" );
	lineto( current.point.x + dx, current.point.y + dy );
	}

    private final double segAng = 5.0;

    /// Append counterclockwise arc.
    public void arc( double cx, double cy, double r, double ang1, double ang2 )
	{
	ang1 = normAngle( ang1 );
	ang2 = normAngle( ang2 );
	if ( ang2 <= ang1 )
	    ang2 += 360.0;
	for ( double a = ang1 ; a < ang2; a += segAng )
	    arcSeg( cx, cy, r, a );
	arcSeg( cx, cy, r, ang2 );
	}

    /// Append clockwise arc.
    public void arcn( double cx, double cy, double r, double ang1, double ang2 )
	{
	ang1 = normAngle( ang1 );
	ang2 = normAngle( ang2 );
	if ( ang2 >= ang1 )
	    ang2 -= 360.0;
	for ( double a = ang1 ; a > ang2; a -= segAng )
	    arcSeg( cx, cy, r, a );
	arcSeg( cx, cy, r, ang2 );
	}

    private void arcSeg( double cx, double cy, double r, double a )
	{
	double x = cx + r * Math.cos( toRadians( a ) );
	double y = cy + r * Math.sin( toRadians( a ) );
	if ( current.point == null )
	    moveto( x, y );
	else
	    try
		{
		lineto( x, y );
		}
	    catch ( Acme.PsgException e )
		{
		// Shouldn't happen.
		throw new InternalError();
		}
	}

    private final double tStep = 0.025;

    /// Append a Bezier cubic section.
    // @exception Acme.PsgException "no current point"
    public void curveto( double x1, double y1, double x2, double y2, double x3, double y3 ) throws PsgException
	{
	if ( current.point == null )
	    throw new PsgException( "no current point" );
	double x0 = current.point.x;
	double y0 = current.point.y;
	double cx = ( x1 - x0 ) * 3.0;
	double cy = ( y1 - y0 ) * 3.0;
	double bx = ( x2 - x1 ) * 3.0 - cx;
	double by = ( y2 - y1 ) * 3.0 - cy;
	double ax = x3 - x0 - cx - bx;
	double ay = y3 - y0 - cy - by;
	for ( double t = 0.0; t < 1.0; t += tStep )
	    curveSeg( ax, ay, bx, by, cx, cy, x0, y0, t );
	curveSeg( ax, ay, bx, by, cx, cy, x0, y0, 1.0 );
	}

    private void curveSeg( double ax, double ay, double bx, double by, double cx, double cy, double x0, double y0, double t )
	{
	double t2 = t * t;
	double t3 = t2 * t;
	double x = ax * t3 + bx * t2 + cx * t + x0;
	double y = ay * t3 + by * t2 + cy * t + y0;
	try
	    {
	    lineto( x, y );
	    }
	catch ( Acme.PsgException e )
	    {
	    // Shouldn't happen.
	    throw new InternalError();
	    }
	}

    /// Relative curveto.
    // @exception Acme.PsgException "no current point"
    public void rcurveto( double dx1, double dy1, double dx2, double dy2, double dx3, double dy3 ) throws PsgException
	{
	if ( current.point == null )
	    throw new PsgException( "no current point" );
	double x0 = current.point.x;
	double y0 = current.point.y;
	curveto( x0 + dx1, y0 + dy1, x0 + dx2, y0 + dy2, x0 + dx3, y0 + dy3 );
	}

    /// Connect current path back to its starting point.
    public void closepath()
	{
	if ( subpathStart != null )
	    path.addElement(
		new PsgPathItem(
		    subpathStart.p.x, subpathStart.p.y,
		    current.linewidth, true ) );
	current.point = null;
	subpathStart = null;
	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -