Java/2D Graphics GUI/Line
Содержание
- 1 A line is drawn using two points
- 2 Dash style line
- 3 Draw a point: use a drawLine() method
- 4 Draw Dashed
- 5 Drawing a Line using Java 2D Graphics API
- 6 Draw Optimized Line
- 7 Line dashes style 2
- 8 Line Dash Style 4
- 9 Line-graph drawable
- 10 Lines Dashes style 3
- 11 Line Styles
- 12 Xsplinefun displays colorful moving splines in a window
A line is drawn using two points
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class LinesDashes1 extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
float[] dash1 = { 2f, 0f, 2f };
g2d.drawLine(20, 40, 250, 40);
BasicStroke bs1 = new BasicStroke(1,
BasicStroke.CAP_BUTT,
BasicStroke.JOIN_ROUND,
1.0f,
dash1,
2f);
g2d.setStroke(bs1);
g2d.drawLine(20, 80, 250, 80);
}
public static void main(String[] args) {
LinesDashes1 lines = new LinesDashes1();
JFrame frame = new JFrame("Lines");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(lines);
frame.setSize(280, 270);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Dash style line
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class LinesDashes1 extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
float[] dash1 = { 2f, 0f, 2f };
g2d.drawLine(20, 40, 250, 40);
BasicStroke bs1 = new BasicStroke(1,
BasicStroke.CAP_BUTT,
BasicStroke.JOIN_ROUND,
1.0f,
dash1,
2f);
g2d.setStroke(bs1);
g2d.drawLine(20, 80, 250, 80);
}
public static void main(String[] args) {
LinesDashes1 lines = new LinesDashes1();
JFrame frame = new JFrame("Lines");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(lines);
frame.setSize(280, 270);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Draw a point: use a drawLine() method
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Points extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.red);
for (int i = 0; i <= 100000; i++) {
Dimension size = getSize();
int w = size.width ;
int h = size.height;
Random r = new Random();
int x = Math.abs(r.nextInt()) % w;
int y = Math.abs(r.nextInt()) % h;
g2d.drawLine(x, y, x, y);
}
}
public static void main(String[] args) {
Points points = new Points();
JFrame frame = new JFrame("Points");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(points);
frame.setSize(250, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Draw Dashed
/*
GNU LESSER GENERAL PUBLIC LICENSE
Copyright (C) 2006 The Lobo Project
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 library 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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Contact info: lobochief@users.sourceforge.net
*/
import java.awt.*;
public class GUITasks {
public static Frame getTopFrame() {
Frame[] frames = Frame.getFrames();
for(int i = 0; i < frames.length; i++) {
if(frames[i].getFocusOwner() != null) {
return frames[i];
}
}
if(frames.length > 0) {
return frames[0];
}
return null;
}
public static void drawDashed(Graphics g, int x1, int y1, int x2, int y2, int dashSize, int gapSize) {
if(x2 < x1) {
int temp = x1;
x1 = x2;
x2 = temp;
}
if(y2 < y1) {
int temp = y1;
y1 = y2;
y2 = temp;
}
int totalDash = dashSize + gapSize;
if(y1 == y2) {
int virtualStartX = (x1 / totalDash) * totalDash;
for(int x = virtualStartX; x < x2; x += totalDash) {
int topX = x + dashSize;
if(topX > x2) {
topX = x2;
}
int firstX = x;
if(firstX < x1) {
firstX = x1;
}
if(firstX < topX) {
g.drawLine(firstX, y1, topX, y1);
}
}
}
else if(x1 == x2) {
int virtualStartY = (y1 / totalDash) * totalDash;
for(int y = virtualStartY; y < y2; y += totalDash) {
int topY = y + dashSize;
if(topY > y2) {
topY = y2;
}
int firstY = y;
if(firstY < y1) {
firstY = y1;
}
if(firstY < topY) {
g.drawLine(x1, firstY, x1, topY);
}
}
}
else {
// Not supported
g.drawLine(x1, y1, x2, y2);
}
}
}
Drawing a Line using Java 2D Graphics API
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
public class Main extends javax.swing.JFrame {
public Main() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setSize(600, 600);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Line2D lin = new Line2D.Float(100, 100, 250, 260);
g2.draw(lin);
}
public static void main(String args[]) {
new Main().setVisible(true);
}
}
Draw Optimized Line
/*
* Copyright (C) 2004 NNL Technology AB
* Visit www.infonode.net for information about InfoNode(R)
* products and how to contact NNL Technology AB.
*
* This program is 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; either version 2
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
// $Id: GraphicsUtil.java,v 1.4 2005/12/04 13:46:04 jesper Exp $
import javax.swing.*;
import java.awt.*;
/**
* @author johan
*/
public class GraphicsUtil {
public static void drawOptimizedLine(Graphics g, int x1, int y1, int x2, int y2) {
if (g.getColor().getAlpha() < 255 && (x1 == x2 || y1 == y2))
g.fillRect(x1 < x2 ? x1 : x2, y1 < y2 ? y1 : y2, Math.abs(x2 - x1) + 1, Math.abs(y2 - y1) + 1);
else
g.drawLine(x1, y1, x2, y2);
}
public static Rectangle calculateIntersectionClip(int x, int y, int width, int height, Shape originalClip) {
Rectangle bounds = originalClip.getBounds();
SwingUtilities.ruputeIntersection(x, y, width, height, bounds);
return bounds;
}
}
Line dashes style 2
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class LinesDashes2 extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawLine(20, 40, 250, 40);
float[] dash2 = { 1f, 1f, 1f };
BasicStroke bs2 = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 1.0f, dash2,2f);
g2d.setStroke(bs2);
g2d.drawLine(20, 20, 250, 20);
}
public static void main(String[] args) {
LinesDashes2 lines = new LinesDashes2();
JFrame frame = new JFrame("Lines");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(lines);
frame.setSize(280, 270);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Line Dash Style 4
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class LinesDashes4 extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
float[] dash4 = { 4f, 4f, 1f };
BasicStroke bs4 = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 1.0f, dash4,
2f);
g2d.setStroke(bs4);
g2d.drawLine(20, 20, 250, 20);
}
public static void main(String[] args) {
LinesDashes4 lines = new LinesDashes4();
JFrame frame = new JFrame("Lines");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(lines);
frame.setSize(280, 270);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Line-graph drawable
/**
*
* LibSparkline : a free Java sparkline chart library
*
*
* Project Info: http://reporting.pentaho.org/libsparkline/
*
* (C) Copyright 2008, by Larry Ogrodnek, Pentaho Corporation and Contributors.
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the Apache License 2.0.
*
* This library 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.
*
* You should have received a copy of the Apache License 2.0 along with this library;
* if not, a online version is available at http://www.apache.org/licenses/
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ------------
* LineGraphDrawable.java
* ------------
*/
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
/**
* A very fast and very simple line-graph drawable. This code is based on the
* LineGraph class writen by Larry Ogrodnek but instead of producing a
* low-resolution image, this class writes the content into a Graphics2D
* context.
*
* @author Thomas Morgner
*/
public class LineGraphDrawable {
private static final int DEFAULT_SPACING = 2;
private int spacing;
private Color color;
private Color background;
private Number[] data;
/**
* Creates a default bargraph drawable with some sensible default colors and
* spacings.
*/
public LineGraphDrawable() {
this.color = Color.black;
this.spacing = DEFAULT_SPACING;
}
/**
* Returns the numeric data for the drawable or null, if the drawable has no
* data.
*
* @return the data.
*/
public Number[] getData() {
return data;
}
/**
* Defines the numeric data for the drawable or null, if the drawable has no
* data.
*
* @param data
* the data (can be null).
*/
public void setData(final Number[] data) {
this.data = data;
}
/**
* Returns the main color for the bars.
*
* @return the main color for the bars, never null.
*/
public Color getColor() {
return color;
}
/**
* Defines the main color for the bars.
*
* @param color
* the main color for the bars, never null.
*/
public void setColor(final Color color) {
if (color == null) {
throw new NullPointerException();
}
this.color = color;
}
/**
* Returns the color for the background of the graph. This property can be
* null, in which case the bar will have a transparent background.
*
* @return color for the background or null, if the graph has a transparent
* background color.
*/
public Color getBackground() {
return background;
}
/**
* Defines the color for the background of the graph. This property can be
* null, in which case the bar will have a transparent background.
*
* @param background
* the background or null, if the graph has a transparent background
* color.
*/
public void setBackground(final Color background) {
this.background = background;
}
/**
* Returns the spacing between the bars.
*
* @return the spacing between the bars.
*/
public int getSpacing() {
return spacing;
}
/**
* Defines the spacing between the bars.
*
* @param spacing
* the spacing between the bars.
*/
public void setSpacing(final int spacing) {
this.spacing = spacing;
}
/**
* Draws the bar-graph into the given Graphics2D context in the given area.
* This method will not draw a graph if the data given is null or empty.
*
* @param graphics
* the graphics context on which the bargraph should be rendered.
* @param drawArea
* the area on which the bargraph should be drawn.
*/
public void draw(final Graphics2D graphics, final Rectangle2D drawArea) {
if (graphics == null) {
throw new NullPointerException();
}
if (drawArea == null) {
throw new NullPointerException();
}
final int height = (int) drawArea.getHeight();
if (height <= 0) {
return;
}
final Graphics2D g2 = (Graphics2D) graphics.create();
if (background != null) {
g2.setPaint(background);
g2.draw(drawArea);
}
if (data == null || data.length == 0) {
g2.dispose();
return;
}
g2.translate(drawArea.getX(), drawArea.getY());
float d = getDivisor(data, height);
final int spacing = getSpacing();
final int w = (((int) drawArea.getWidth()) - (spacing * (data.length - 1))) / (data.length - 1);
float min = Float.MAX_VALUE;
for (int index = 0; index < data.length; index++) {
Number i = data[index];
if (i == null) {
continue;
}
final float value = i.floatValue();
if (value < min) {
min = value;
}
}
int x = 0;
int y = -1;
if (d == 0.0) {
// special case -- a horizontal straight line
d = 1.0f;
y = -height / 2;
}
final Line2D.Double line = new Line2D.Double();
for (int i = 0; i < data.length - 1; i++) {
final int px1 = x;
x += (w + spacing);
final int px2 = x;
g2.setPaint(color);
final Number number = data[i];
final Number nextNumber = data[i + 1];
if (number == null && nextNumber == null) {
final float delta = height - ((0 - min) / d);
line.setLine(px1, y + delta, px2, y + delta);
} else if (number == null) {
line.setLine(px1, y + (height - ((0 - min) / d)), px2, y
+ (height - ((nextNumber.floatValue() - min) / d)));
} else if (nextNumber == null) {
line.setLine(px1, y + (height - ((number.floatValue() - min) / d)), px2, y
+ (height - ((0 - min) / d)));
} else {
line.setLine(px1, y + (height - ((number.floatValue() - min) / d)), px2, y
+ (height - ((nextNumber.floatValue() - min) / d)));
}
g2.draw(line);
}
g2.dispose();
}
/**
* Computes the scale factor to scale the given numeric data into the target
* height.
*
* @param data
* the numeric data.
* @param height
* the target height of the graph.
* @return the scale factor.
*/
public static float getDivisor(final Number[] data, final int height) {
if (data == null) {
throw new NullPointerException("Data array must not be null.");
}
if (height < 1) {
throw new IndexOutOfBoundsException("Height must be greater or equal to 1");
}
float max = Float.MIN_VALUE;
float min = Float.MAX_VALUE;
for (int index = 0; index < data.length; index++) {
Number i = data[index];
if (i == null) {
continue;
}
final float numValue = i.floatValue();
if (numValue < min) {
min = numValue;
}
if (numValue > max) {
max = numValue;
}
}
if (max <= min) {
return 1.0f;
}
if (height == 1) {
return 0;
}
return (max - min) / (height - 1);
}
}
Lines Dashes style 3
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class LinesDashes3 extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
float[] dash3 = { 4f, 0f, 2f };
BasicStroke bs3 = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 1.0f, dash3,
2f);
g2d.setStroke(bs3);
g2d.drawLine(20, 60, 250, 60);
}
public static void main(String[] args) {
LinesDashes3 lines = new LinesDashes3();
JFrame frame = new JFrame("Lines");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(lines);
frame.setSize(280, 270);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Line Styles
/*
* Copyright (c) 2000 David Flanagan. All rights reserved.
* This code is from the book Java Examples in a Nutshell, 2nd Edition.
* It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
* You may study, use, and modify it for any non-commercial purpose.
* You may distribute it non-commercially as long as you retain this notice.
* For a commercial use license, or to purchase the book (recommended),
* visit http://www.davidflanagan.ru/javaexamples2.
*/
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.GeneralPath;
import javax.swing.JFrame;
import javax.swing.JPanel;
/** A demonstration of Java2D line styles */
public class LineStyles extends JPanel{
public String getName() {
return "LineStyles";
}
public int getWidth() {
return 450;
}
public int getHeight() {
return 180;
}
int[] xpoints = new int[] { 0, 50, 100 }; // X coordinates of our shape
int[] ypoints = new int[] { 75, 0, 75 }; // Y coordinates of our shape
// Here are three different line styles we will demonstrate
// They are thick lines with different cap and join styles
Stroke[] linestyles = new Stroke[] {
new BasicStroke(25.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL),
new BasicStroke(25.0f, BasicStroke.CAP_SQUARE,
BasicStroke.JOIN_MITER),
new BasicStroke(25.0f, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND), };
// Another line style: a 2 pixel-wide dot-dashed line
Stroke thindashed = new BasicStroke(2.0f, // line width
/* cap style */BasicStroke.CAP_BUTT,
/* join style, miter limit */BasicStroke.JOIN_BEVEL, 1.0f,
/* the dash pattern */new float[] { 8.0f, 3.0f, 2.0f, 3.0f },
/* the dash phase */0.0f); /* on 8, off 3, on 2, off 3 */
// Labels to appear in the diagram, and the font to use to display them.
Font font = new Font("Helvetica", Font.BOLD, 12);
String[] capNames = new String[] { "CAP_BUTT", "CAP_SQUARE", "CAP_ROUND" };
String[] joinNames = new String[] { "JOIN_BEVEL", "JOIN_MITER",
"JOIN_ROUND" };
/** This method draws the example figure */
public void paint(Graphics g1) {
Graphics2D g = (Graphics2D) g1;
// Use anti-aliasing to avoid "jaggies" in the lines
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// Define the shape to draw
GeneralPath shape = new GeneralPath();
shape.moveTo(xpoints[0], ypoints[0]); // start at point 0
shape.lineTo(xpoints[1], ypoints[1]); // draw a line to point 1
shape.lineTo(xpoints[2], ypoints[2]); // and then on to point 2
// Move the origin to the right and down, creating a margin
g.translate(20, 40);
// Now loop, drawing our shape with the three different line styles
for (int i = 0; i < linestyles.length; i++) {
g.setColor(Color.gray); // Draw a gray line
g.setStroke(linestyles[i]); // Select the line style to use
g.draw(shape); // Draw the shape
g.setColor(Color.black); // Now use black
g.setStroke(thindashed); // And the thin dashed line
g.draw(shape); // And draw the shape again.
// Highlight the location of the vertexes of the shape
// This accentuates the cap and join styles we"re demonstrating
for (int j = 0; j < xpoints.length; j++)
g.fillRect(xpoints[j] - 2, ypoints[j] - 2, 5, 5);
g.drawString(capNames[i], 5, 105); // Label the cap style
g.drawString(joinNames[i], 5, 120); // Label the join style
g.translate(150, 0); // Move over to the right before looping again
}
}
public static void main(String[] a){
JFrame f = new JFrame();
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.setContentPane(new LineStyles());
f.setSize(450,200);
f.setVisible(true);
}
}
Xsplinefun displays colorful moving splines in a window
/**
* Xsplinefun displays colorful moving splines in a window.
*
* Taken from xsplinefun, Distribution of 02may92, by Jef Poskanzer,
* jef@netcom.ru, jef@well.sf.ca.us
*
* @copyright (C) 1992 by Jef Poskanzer
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation. This software is provided "as is" without express or implied
* warranty.
*
* First step in converting to Java was to junk all the X Windows stuff; in the
* process we lost all the customization (need to re-add with getopt?).
*/
public class XSplineFun {
public static final int POINTS = 20;
public static final int DEFAULT_MAX_COLORS = 20;
/* Spline-fun smarts. */
static int x[] = new int [POINTS];
static int y[]= new int [POINTS];
static int dx[] = new int [POINTS];
static int dy[]= new int [POINTS];
static int nred, ngreen, nblue, dred, dgreen, dblue;
static int color;
static Color xcolors[] = new Color[DEFAULT_MAX_COLORS];
public static void main(String[] av) {
Frame f = new Frame("Spline Fun");
XSplineFun xf = new XSplineFun();
xf.init_splines();
f.add(xf);
while(true)
try {
xf.move_splines();
Thread.sleep(150); // msec
} catch (Exception e) {
System.out.println(e);
}
}
static void
init_splines()
{
int i;
/* Initialize points. */
for ( i = 0; i < POINTS; ++i )
{
x[i] = random() % width;
y[i] = random() % height;
dx[i] = random() % ( MAX_DELTA * 2 ) - MAX_DELTA;
if ( dx[i] <= 0 ) --dx[i];
dy[i] = random() % ( MAX_DELTA * 2 ) - MAX_DELTA;
if ( dy[i] <= 0 ) --dy[i];
}
/* Initalize colors. */
for ( color = 0; color < ncolors; ++color )
{
xcolors[color].red = xcolors[color].green = xcolors[color].blue = 0;
xcolors[color].pixel = pixels[color];
xcolors[color].flags = DoRed|DoGreen|DoBlue;
}
color = 0;
nred = ngreen = nblue = 0;
dred = random() % ( MAX_COLOR_DELTA * 2 ) - MAX_COLOR_DELTA;
if ( dred <= 0 ) --dred;
dgreen = random() % ( MAX_COLOR_DELTA * 2 ) - MAX_COLOR_DELTA;
if ( dgreen <= 0 ) --dgreen;
dblue = random() % ( MAX_COLOR_DELTA * 2 ) - MAX_COLOR_DELTA;
if ( dblue <= 0 ) --dblue;
}
static void
rotate_colormap()
{
int t, i;
if ( forwards )
{
t = xcolors[0].pixel;
for ( i = 0; i < ncolors - 1; ++i )
xcolors[i].pixel = xcolors[i + 1].pixel;
xcolors[ncolors - 1].pixel = t;
XStoreColors(display, cmap, xcolors, ncolors );
}
else if ( backwards )
{
t = xcolors[ncolors - 1].pixel;
for ( i = ncolors - 1; i > 0; --i )
xcolors[i].pixel = xcolors[i - 1].pixel;
xcolors[0].pixel = t;
XStoreColors(display, cmap, xcolors, ncolors );
}
}
static void
new_color()
{
int t;
for ( ; ; )
{
t = (int) nred + dred;
if ( t >= 0 && t < 65536 ) break;
dred = random() % ( MAX_COLOR_DELTA * 2 ) - MAX_COLOR_DELTA;
if ( dred <= 0 ) --dred;
}
xcolors[color].red = nred = t;
for ( ; ; )
{
t = (int) ngreen + dgreen;
if ( t >= 0 && t < 65536 ) break;
dgreen = random() % ( MAX_COLOR_DELTA * 2 ) - MAX_COLOR_DELTA;
if ( dgreen <= 0 ) --dgreen;
}
xcolors[color].green = ngreen = t;
for ( ; ; )
{
t = (int) nblue + dblue;
if ( t >= 0 && t < 65536 ) break;
dblue = random() % ( MAX_COLOR_DELTA * 2 ) - MAX_COLOR_DELTA;
if ( dblue <= 0 ) --dblue;
}
xcolors[color].blue = nblue = t;
XStoreColor(display, cmap, &(xcolors[color]) );
XSetForeground( display, gc, xcolors[color].pixel );
if ( ++color >= ncolors ) color -= ncolors;
}
static void
move_splines()
{
int i, t, px, py, zx, zy, nx, ny;
/* Rotate colormap if necessary. */
rotate_colormap();
/* Choose new color. */
new_color();
/* Backwards rotation requires two new colors each loop. */
if ( backwards )
new_color();
/* Move the points. */
for ( i = 0; i < POINTS; i++ )
{
for ( ; ; )
{
t = x[i] + dx[i];
if ( t >= 0 && t < width ) break;
dx[i] = random() % ( MAX_DELTA * 2 ) - MAX_DELTA;
if ( dx[i] <= 0 ) --dx[i];
}
x[i] = t;
for ( ; ; )
{
t = y[i] + dy[i];
if ( t >= 0 && t < height ) break;
dy[i] = random() % ( MAX_DELTA * 2 ) - MAX_DELTA;
if ( dy[i] <= 0 ) --dy[i];
}
y[i] = t;
}
/* Draw the figure. */
px = zx = ( x[0] + x[POINTS-1] ) / 2;
py = zy = ( y[0] + y[POINTS-1] ) / 2;
for ( i = 0; i < POINTS-1; ++i )
{
nx = ( x[i+1] + x[i] ) / 2;
ny = ( y[i+1] + y[i] ) / 2;
XDrawSpline(g, px, py, x[i], y[i], nx, ny );
px = nx;
py = ny;
}
XDrawSpline(g, px, py, x[POINTS-1], y[POINTS-1], zx, zy );
}
/* X spline routine. */
int abs(x) {
return x < 0 ? -x : x;
}
static void
XDrawSpline(Graphics g, int x0, y0, x1, y1, x2, y2) {
register int xa, ya, xb, yb, xc, yc, xp, yp;
xa = ( x0 + x1 ) / 2;
ya = ( y0 + y1 ) / 2;
xc = ( x1 + x2 ) / 2;
yc = ( y1 + y2 ) / 2;
xb = ( xa + xc ) / 2;
yb = ( ya + yc ) / 2;
xp = ( x0 + xb ) / 2;
yp = ( y0 + yb ) / 2;
if ( abs( xa - xp ) + abs( ya - yp ) > SPLINE_THRESH )
XDrawSpline( display, d, gc, x0, y0, xa, ya, xb, yb );
else
XDrawLine( display, d, gc, x0, y0, xb, yb );
xp = ( x2 + xb ) / 2;
yp = ( y2 + yb ) / 2;
if ( abs( xc - xp ) + abs( yc - yp ) > SPLINE_THRESH )
XDrawSpline( display, d, gc, xb, yb, xc, yc, x2, y2 );
else
XDrawLine( display, d, gc, xb, yb, x2, y2 );
}
}