Java/2D Graphics GUI/Area Calculation

Материал из Java эксперт
Перейти к: навигация, поиск

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>