Java/2D Graphics GUI/Area Calculation
Содержание
A Java implementation of the X11 region
<source lang="java"> /*
* (C) 2004 - Geotechnical Software Services * * This code 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 code 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 program; if not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. */
//package no.geosoft.cc.geometry;
/**
* A Region is simply an area, as the name implies, and is * implemented as a so called "y-x-banded" array of rectangles; Each Region * is made up of a certain number of rectangles sorted by y coordinate first, * and then by x coordinate.*
* Furthermore, the rectangles are banded such that every rectangle with a * given upper-left y coordinate (y1) will have the same lower-right y * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, * it will span the entire vertical distance of the band. This means that * some areas that could be merged into a taller rectangle will be represented * as several shorter rectangles to account for shorter rectangles to its * left or right but within its "vertical scope". * <p> * An added constraint on the rectangles is that they must cover as much * horizontal area as possible. E.g. no two rectangles in a band are allowed * to touch. Whenever possible, bands will be merged together to cover a * greater vertical distance (and thus reduce the number of rectangles). * Two bands can be merged only if the bottom of one touches the top of the * other and they have rectangles in the same places (of the same width, of * course). This maintains the y-x-banding. * <p> * Region operations includes add (union), subtract, intersect, and * exclusive-or. * <p> * This class corresponds to Region.c of the X11 distribution and the * implemntation is based on it. * <p> * The Region is essentially equivalent to an AWT Area * but with different back-end implementation. Becnhmarking proves it more * than 100 times faster than AWT Area for binary CAG operations, * <p> * Thanks to: *
-
*
- Bryan Lin @ China Minmetals Corporation - for identifying * synchronization errors when run on the MS WindowsXP platform. *
- Maxim Butov @ Belhard - for identifying error in the * isInside(Rect) method. *
* * @author */
//public class Rect {
public int x; public int y; public int height; public int width;
/** * Create a rectangle. * * @param x X coordinate of upper left corner. * @param y Y coordinate of upper left corner. * @param width Width of rectangle. * @param height Height of rectangle. */ public Rect (int x, int y, int width, int height) { set (x, y, width, height); }
/** * Create a default rectangle. */ public Rect() { this (0, 0, 0, 0); } /** * Create a rectangle as a copy of the specified rectangle. * * @param rectangle */ public Rect (Rect rectangle) { this (rectangle.x, rectangle.y, rectangle.width, rectangle.height); } /** * Create a rectnagle based on specified box. * * @param box Box to create rectangle from. */ public Rect (Box box) { this (box.x1, box.y1, box.x2 - box.x1, box.y2 - box.y1); } /** * Copy the specified rectangle. * * @param rectangle Rectangle to copy. */ public void copy (Rect rectangle) { this.x = rectangle.x; this.y = rectangle.y; this.width = rectangle.width; this.height = rectangle.height; } /** * Clone this rectangle * * @return Clone of this rectangle. */ public Object clone() { return new Rect (x, y, width, height); }
/** * Check if this rectangle equals the specified object. * * @param object Object to chack. * @return True if the two equals, false otherwise. */ public boolean equals (Object object) { Rect rectangle = (Rect) object; return this.x == rectangle.x && this.y == rectangle.y && this.width == rectangle.width && this.height == rectangle.height; }
/** * Return true if this rectangle is empty. * * @return True if this rectangle is empty, false otherwise. */ public boolean isEmpty() { return width <= 0 || height <= 0; } /** * Expand this rectangle the specified amount in each direction. * * @param dx Amount to expand to left and right. * @param dy Amount to expand on top and botton. */ public void expand (int dx, int dy) { x -= dx; y -= dy; width += dx + dx; height += dy + dy; } /** * Set the parameters for this rectangle. * * @param x X coordinate of upper left corner. * @param y Y coordinate of upper left corner. * @param width Width of rectangle. * @param height Height of rectangle. */ public void set (int x, int y, int width, int height) { this.x = x; this.y = y; this.width = width; this.height = height; } /** * Set this rectangle as extent of specified polyline. * * @param xArray X coordinates of polyline. * @param yArray Y coordinates of polyline. */ public void set (int xArray[], int yArray[]) { int minX = Integer.MAX_VALUE; int maxX = Integer.MIN_VALUE; int minY = Integer.MAX_VALUE; int maxY = Integer.MIN_VALUE; for (int i = 0; i < xArray.length; i++) { if (xArray[i] < minX) minX = xArray[i]; if (xArray[i] > maxX) maxX = xArray[i]; if (yArray[i] < minY) minY = yArray[i]; if (yArray[i] > maxY) maxY = yArray[i]; } x = minX; y = minY; width = maxX - minX + 1; height = maxY - minY + 1; }
/** * Return X coordinate of center of this rectangle. * * @return X coordinate of center of this rectangle. */ public int getCenterX() { return x + (int) Math.floor (width / 2.0); } /** * Return Y coordinate of center of this rectangle. * * @return Y coordinate of center of this rectangle. */ public int getCenterY() { return y + (int) Math.floor (height / 2.0); } /** * Return a string representation of this rectangle. * * @return String representation of this rectangle. */ public String toString() { return new String ("Rectangle: x= " + x + " y=" + y + " width=" + width + " height=" + height); }
}
</source>
Area Add
<source lang="java"> import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.geom.Area; import java.awt.geom.Ellipse2D; import javax.swing.JApplet; import javax.swing.JFrame; public class AreaAdd extends JApplet {
Ellipse2D.Double circle = new Ellipse2D.Double(); Ellipse2D.Double oval = new Ellipse2D.Double(); Area circ = new Area(circle); Area ov = new Area(oval); public void init() { setBackground(Color.white); } public void paint (Graphics g) { Graphics2D g2 = (Graphics2D) g; double halfWdith = getSize().width/2; double halfHeight = getSize().height/2; circle.setFrame(halfWdith-25, halfHeight, 50.0, 50.0); oval.setFrame(halfWdith-19, halfHeight-20, 40.0, 70.0); circ = new Area(circle); ov = new Area(oval); circ.add(ov); g2.fill(circ); } public static void main(String s[]) { JFrame f = new JFrame("Pear"); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) {System.exit(0);} }); JApplet applet = new AreaAdd(); f.getContentPane().add("Center", applet); applet.init(); f.pack(); f.setSize(new Dimension(150,200)); f.show(); }
}
</source>
Area Calculation: Add, Subtract, XOR
<source lang="java"> import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Canvas; import java.awt.Color; import java.awt.Container; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.Area; import java.awt.geom.Ellipse2D; import java.awt.geom.GeneralPath; import javax.swing.ButtonGroup; import javax.swing.JApplet; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.border.TitledBorder; public class TArea extends JApplet implements ActionListener {
DrawingCanvas canvas; JRadioButton addButton, subtractButton, intersectButton, exclusiveORButton, resetButton; public static void main(String[] a) { JFrame f = new JFrame(); TArea area = new TArea(); area.init(); f.getContentPane().add(area); f.setDefaultCloseOperation(1); f.setSize(650, 450); f.setVisible(true); } public void init() { Container container = getContentPane(); JPanel panel = new JPanel(); panel.setLayout(new GridLayout(2, 2)); resetButton = new JRadioButton("Reset", true); addButton = new JRadioButton("Add"); subtractButton = new JRadioButton("Subtract"); intersectButton = new JRadioButton("Intersect"); exclusiveORButton = new JRadioButton("ExclusiveOR"); ButtonGroup group = new ButtonGroup(); group.add(resetButton); group.add(addButton); group.add(subtractButton); group.add(intersectButton); group.add(exclusiveORButton); group.add(resetButton); resetButton.addActionListener(this); addButton.addActionListener(this); subtractButton.addActionListener(this); intersectButton.addActionListener(this); exclusiveORButton.addActionListener(this); panel.add(addButton); panel.add(subtractButton); panel.add(intersectButton); panel.add(exclusiveORButton); container.add(panel, BorderLayout.NORTH); container.add(resetButton, BorderLayout.SOUTH); canvas = new DrawingCanvas(); container.add(canvas); } class DrawingCanvas extends Canvas { GeneralPath gp; Ellipse2D ellipse; Area area1, area2; boolean drawFlag = true; boolean fillFlag = false; public DrawingCanvas() { setBackground(Color.white); setSize(350, 250); int w = getWidth(); int h = getHeight(); gp = new GeneralPath(); gp.moveTo(w / 8, h / 2); gp.lineTo(w / 2, h / 4); gp.lineTo(7 * w / 8, h / 2); gp.lineTo(w / 2, 3 * h / 4); gp.closePath(); area1 = new Area(gp); ellipse = new Ellipse2D.Double(w / 4, h / 4, w / 2, h / 2); area2 = new Area(ellipse); // Ellipse area object } public void paint(Graphics g) { Graphics2D g2D = (Graphics2D) g; g2D.setStroke(new BasicStroke(2.0f)); if (drawFlag) { g2D.draw(area1); g2D.draw(area2); } if (fillFlag) g2D.fill(area1); } } public void actionPerformed(ActionEvent e) { JRadioButton temp = (JRadioButton) e.getSource(); if (temp.equals(addButton)) { canvas.area1 = new Area(canvas.gp); canvas.area1.add(canvas.area2); canvas.drawFlag = false; canvas.fillFlag = true; canvas.repaint(); } else if (temp.equals(subtractButton)) { canvas.area1 = new Area(canvas.gp); canvas.area1.subtract(canvas.area2); canvas.drawFlag = false; canvas.fillFlag = true; canvas.repaint(); } else if (temp.equals(intersectButton)) { canvas.area1 = new Area(canvas.gp); canvas.area1.intersect(canvas.area2); canvas.drawFlag = false; canvas.fillFlag = true; canvas.repaint(); } else if (temp.equals(exclusiveORButton)) { canvas.area1 = new Area(canvas.gp); canvas.area1.exclusiveOr(canvas.area2); canvas.drawFlag = false; canvas.fillFlag = true; canvas.repaint(); } else if (temp.equals(resetButton)) { if (canvas.drawFlag == false) { canvas.area1 = new Area(canvas.gp); canvas.drawFlag = true; canvas.fillFlag = false; canvas.repaint(); } } }
}
</source>
Area Intersect
<source lang="java"> import java.awt.*; import java.awt.event.*; import java.awt.font.*; import java.awt.geom.*; import javax.swing.*; public class AreaIntersect extends JApplet {
Ellipse2D.Double leaf = new Ellipse2D.Double(); Ellipse2D.Double stem = new Ellipse2D.Double(); Area leaf1 = new Area(leaf); Area leaf2 = new Area(leaf); public void init() { setBackground(Color.white); } public void paint (Graphics g) { Graphics2D g2 = (Graphics2D) g; double halfWdith = getSize().width/2; double halfHeight = getSize().height/2; g2.setColor(Color.green); leaf.setFrame(halfWdith-16, halfHeight-29, 15.0, 15.0); leaf1 = new Area(leaf); leaf.setFrame(halfWdith-14, halfHeight-47, 30.0, 30.0); leaf2 = new Area(leaf); leaf1.intersect(leaf2); g2.fill(leaf1); } public static void main(String s[]) { JFrame f = new JFrame("Pear"); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) {System.exit(0);} }); JApplet applet = new AreaIntersect(); f.getContentPane().add("Center", applet); applet.init(); f.pack(); f.setSize(new Dimension(150,200)); f.show(); }
}
</source>
Area Subtract
<source lang="java"> import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.geom.Area; import java.awt.geom.Ellipse2D; import javax.swing.JApplet; import javax.swing.JFrame; public class AreaSubtract extends JApplet {
Ellipse2D.Double stem = new Ellipse2D.Double(); Area st1 = new Area(stem); Area st2 = new Area(stem); public void init() { setBackground(Color.white); } public void paint (Graphics g) { Graphics2D g2 = (Graphics2D) g; double halfWdith = getSize().width/2; double halfHeight = getSize().height/2; stem.setFrame(halfWdith, halfHeight-42, 40.0, 40.0); st1 = new Area(stem); stem.setFrame(halfWdith+3, halfHeight-47, 50.0, 50.0); st2 = new Area(stem); st1.subtract(st2); g2.fill(st1); g2.setColor(Color.yellow); } public static void main(String s[]) { JFrame f = new JFrame("Pear"); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) {System.exit(0);} }); JApplet applet = new AreaSubtract(); f.getContentPane().add("Center", applet); applet.init(); f.pack(); f.setSize(new Dimension(150,200)); f.show(); }
}
</source>