Java/2D Graphics GUI/Shape

Материал из Java эксперт
Версия от 18:01, 31 мая 2010; (обсуждение)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

Содержание

Arc demonstration: scale, move, rotate, sheer

     
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.ruponent;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Arc2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JApplet;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class ArcApp extends JPanel {
  MyCanvas canvas;
  JComboBox arcBox, fillBox;
  JSlider sliderX, sliderY, sliderWidth, sliderHeight, sliderT0, sliderT;
  String[] arcLabels = { "Open", "Chord", "Pie" };
  int[] arcTypes = { Arc2D.OPEN, Arc2D.CHORD, Arc2D.PIE };
  String[] colorLabels = { "Black", "White", "Red", "Green", "Blue" };
  Color[] colors = { Color.black, Color.white, Color.red, Color.green,
      Color.blue };
  public ArcApp() {
    super(new BorderLayout());
    canvas = new MyCanvas();
        int width = 600;
        int height = 55;
    sliderX = setSlider(0, width, width / 4, width / 2, width / 4);
    sliderY = setSlider(0, height, height / 4,
        height / 2, height / 4);
    sliderWidth = setSlider(0, width, width / 2, width / 2, width / 4);
    sliderHeight = setSlider(0, height, height / 2,
        height / 2, height / 4);
    sliderT0 = setSlider(0, 360, 45, 180, 45);
    sliderT = setSlider(0, 360, 135, 180, 45);
    JPanel panel1 = new JPanel();
    panel1.setLayout(new GridLayout(3, 3));
    panel1.add(new JLabel("Location (x,y): ", JLabel.RIGHT));
    panel1.add(sliderX);
    panel1.add(sliderY);
    panel1.add(new JLabel("Size (w,h): ", JLabel.RIGHT));
    panel1.add(sliderWidth);
    panel1.add(sliderHeight);
    panel1.add(new JLabel("Angles (Th0, Th): ", JLabel.RIGHT));
    panel1.add(sliderT0);
    panel1.add(sliderT);
    add(panel1, BorderLayout.NORTH);
    arcBox = new JComboBox(arcLabels);
    arcBox.setSelectedIndex(0);
    arcBox.setAlignmentX(Component.LEFT_ALIGNMENT);
    arcBox.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        JComboBox cb = (JComboBox) e.getSource();
        canvas.arcType = arcTypes[cb.getSelectedIndex()];
        canvas.repaint();
      }
    });
    fillBox = new JComboBox(colorLabels);
    fillBox.setSelectedIndex(0);
    fillBox.setAlignmentX(Component.LEFT_ALIGNMENT);
    fillBox.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        JComboBox cb = (JComboBox) e.getSource();
        canvas.fillColor = colors[cb.getSelectedIndex()];
        canvas.repaint();
      }
    });
    JPanel panel2 = new JPanel();
    panel2.setLayout(new GridLayout(1, 4));
    panel2.add(new JLabel("Arc Type: ", JLabel.RIGHT));
    panel2.add(arcBox);
    panel2.add(new JLabel("Fill Type: ", JLabel.RIGHT));
    panel2.add(fillBox);
    add(panel2, BorderLayout.SOUTH);
    add(canvas,BorderLayout.CENTER);
  }
  public JSlider setSlider(int min, int max, int init, int mjrTkSp,
      int mnrTkSp) {
    JSlider slider = new JSlider(JSlider.HORIZONTAL, min, max, init);
    slider.setPaintTicks(true);
    slider.setMajorTickSpacing(mjrTkSp);
    slider.setMinorTickSpacing(mnrTkSp);
    slider.setPaintLabels(true);
    slider.addChangeListener(new SliderListener());
    return slider;
  }
  class MyCanvas extends JLabel {
    Arc2D arc;
    double x, y, w, h, startAngle, extent; 
    Color fillColor;
    int arcType;
    Rectangle2D boundingRec = null;
    public MyCanvas() {
      x = 700 / 4;
      y = 550 / 4;
      w = 600 / 2;
      h = 550 / 2;
      startAngle = 0;
      extent = 135; 
      arcType = Arc2D.OPEN;
      fillColor = Color.black;
      setBackground(Color.white);
    }
    public void paint(Graphics g) {
      Graphics2D g2D = (Graphics2D) g;
      g2D.setColor(Color.white);
      g2D.fill(new Rectangle(getBounds()));
      
      arc = new Arc2D.Double(x, y, w, h, startAngle, extent, arcType);
      if (fillColor == Color.white || arcType == Arc2D.OPEN) {
        g2D.setColor(Color.black);
        g2D.draw(arc);
      } else {
        g2D.setColor(fillColor);
        g2D.fill(arc);
      }
      boundingRec = arc.getBounds2D();
      drawHighlightSquares(g2D, boundingRec);
    }
    public void drawHighlightSquares(Graphics2D g2D, Rectangle2D r) {
      double x = r.getX();
      double y = r.getY();
      double w = r.getWidth();
      double h = r.getHeight();
      g2D.setColor(Color.black);
      g2D.fill(new Rectangle.Double(x - 3.0, y - 3.0, 6.0, 6.0));
      g2D
          .fill(new Rectangle.Double(x + w * 0.5 - 3.0, y - 3.0, 6.0,
              6.0));
      g2D.fill(new Rectangle.Double(x + w - 3.0, y - 3.0, 6.0, 6.0));
      g2D
          .fill(new Rectangle.Double(x - 3.0, y + h * 0.5 - 3.0, 6.0,
              6.0));
      g2D.fill(new Rectangle.Double(x + w - 3.0, y + h * 0.5 - 3.0, 6.0,
          6.0));
      g2D.fill(new Rectangle.Double(x - 3.0, y + h - 3.0, 6.0, 6.0));
      g2D.fill(new Rectangle.Double(x + w * 0.5 - 3.0, y + h - 3.0, 6.0,
          6.0));
      g2D.fill(new Rectangle.Double(x + w - 3.0, y + h - 3.0, 6.0, 6.0));
    }
  }
  class SliderListener implements ChangeListener {
    public void stateChanged(ChangeEvent e) {
      JSlider slider = (JSlider) e.getSource();
      if (slider == sliderX)
        canvas.x = slider.getValue();
      else if (slider == sliderY)
        canvas.y = slider.getValue();
      else if (slider == sliderWidth)
        canvas.w = slider.getValue();
      else if (slider == sliderHeight)
        canvas.h = slider.getValue();
      else if (slider == sliderT0)
        canvas.startAngle = slider.getValue();
      else if (slider == sliderT)
        canvas.extent = slider.getValue();
      canvas.revalidate();
      canvas.repaint();
    }
  }
  public static void main (String[] a){
    JFrame f = new JFrame();
    f.getContentPane().add(new ArcApp());
    f.setDefaultCloseOperation(1);
    f.setSize(700, 550);
    f.setVisible(true);  
  }
}



Calculate Intersection Clip

    
/*
 * 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;
  }
}



Change font

     
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class FontPanel extends JPanel {
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Font f = new Font("SansSerif", Font.BOLD, 14);
    Font fi = new Font("SansSerif", Font.BOLD + Font.ITALIC, 14);
    FontMetrics fm = g.getFontMetrics(f);
    FontMetrics fim = g.getFontMetrics(fi);
    String s1 = "Java ";
    String s2 = "Source and Support";
    String s3 = " at www.jexp.ru";
    int width1 = fm.stringWidth(s1);
    int width2 = fim.stringWidth(s2);
    int width3 = fm.stringWidth(s3);
    Dimension d = getSize();
    int cx = (d.width - width1 - width2 - width3) / 2;
    int cy = (d.height - fm.getHeight()) / 2 + fm.getAscent();
    g.setFont(f);
    g.drawString(s1, cx, cy);
    cx += width1;
    g.setFont(fi);
    g.drawString(s2, cx, cy);
    cx += width2;
    g.setFont(f);
    g.drawString(s3, cx, cy);
  }
  public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setTitle("NotHelloWorld2");
    frame.setSize(350, 200);
    frame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    Container contentPane = frame.getContentPane();
    contentPane.add(new FontPanel());
    frame.show();
  }
}



Checks, whether the given rectangle1 fully contains rectangle 2 (even if rectangle 2 has a height or width of zero!).

   
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
 *
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
 * in the United States and other countries.]
 *
 * -------------------
 * ShapeUtilities.java
 * -------------------
 * (C)opyright 2003-2008, by Object Refinery Limited and Contributors.
 *
 * Original Author:  David Gilbert (for Object Refinery Limited);
 * Contributor(s):   -;
 *
 * $Id: ShapeUtilities.java,v 1.18 2008/06/02 06:58:28 mungady Exp $
 *
 * Changes
 * -------
 * 13-Aug-2003 : Version 1 (DG);
 * 16-Mar-2004 : Moved rotateShape() from RefineryUtilities.java to here (DG);
 * 13-May-2004 : Added new shape creation methods (DG);
 * 30-Sep-2004 : Added createLineRegion() method (DG);
 *               Moved drawRotatedShape() method from RefineryUtilities class
 *               to this class (DG);
 * 04-Oct-2004 : Renamed ShapeUtils --> ShapeUtilities (DG);
 * 26-Oct-2004 : Added a method to test the equality of two Line2D
 *               instances (DG);
 * 10-Nov-2004 : Added new translateShape() and equal(Ellipse2D, Ellipse2D)
 *               methods (DG);
 * 11-Nov-2004 : Renamed translateShape() --> createTranslatedShape() (DG);
 * 07-Jan-2005 : Minor Javadoc fix (DG);
 * 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
 * 21-Jan-2005 : Modified return type of RectangleAnchor.coordinates()
 *               method (DG);
 * 22-Feb-2005 : Added equality tests for Arc2D and GeneralPath (DG);
 * 16-Mar-2005 : Fixed bug where equal(Shape, Shape) fails for two Polygon
 *               instances (DG);
 * 01-Jun-2008 : Fixed bug in equal(GeneralPath, GeneralPath) method (DG);
 *
 */
import java.awt.Shape;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
/**
 * Utility methods for {@link Shape} objects.
 *
 * @author David Gilbert
 */
public class Main {

  /**
   * Checks, whether the given rectangle1 fully contains rectangle 2
   * (even if rectangle 2 has a height or width of zero!).
   *
   * @param rect1  the first rectangle.
   * @param rect2  the second rectangle.
   *
   * @return A boolean.
   */
  public static boolean contains(final Rectangle2D rect1,
                                 final Rectangle2D rect2) {
      final double x0 = rect1.getX();
      final double y0 = rect1.getY();
      final double x = rect2.getX();
      final double y = rect2.getY();
      final double w = rect2.getWidth();
      final double h = rect2.getHeight();
      return ((x >= x0) && (y >= y0)
              && ((x + w) <= (x0 + rect1.getWidth()))
              && ((y + h) <= (y0 + rect1.getHeight())));
  }
}



Combining Shapes

     
import java.awt.Rectangle;
import java.awt.geom.Area;
public class BasicShapes {
  public static void main(String[] args) {
    Area shape = new Area(new Rectangle(1, 1, 1, 1));
    shape.add(new Area(new Rectangle(1, 1, 1, 1)));
    shape.subtract(new Area(new Rectangle(1, 1, 1, 1)));
    shape.intersect(new Area(new Rectangle(1, 1, 1, 1)));
    shape.exclusiveOr(new Area(new Rectangle(1, 1, 1, 1)));
  }
}



Compares two ellipses and returns true if they are equal or both null.

   
import java.awt.geom.Ellipse2D;
public class Main {

  /**
   * Compares two ellipses and returns <code>true</code> if they are equal or
   * both <code>null</code>.
   *
   * @param e1  the first ellipse (<code>null</code> permitted).
   * @param e2  the second ellipse (<code>null</code> permitted).
   *
   * @return A boolean.
   */
  public static boolean equal(final Ellipse2D e1, final Ellipse2D e2) {
      if (e1 == null) {
          return (e2 == null);
      }
      if (e2 == null) {
          return false;
      }
      if (!e1.getFrame().equals(e2.getFrame())) {
          return false;
      }
      return true;
  }
}



Compares two lines are returns true if they are equal or both null.

   
import java.awt.geom.Line2D;
public class Main {
  /**
   * Compares two lines are returns <code>true</code> if they are equal or
   * both <code>null</code>.
   *
   * @param l1  the first line (<code>null</code> permitted).
   * @param l2  the second line (<code>null</code> permitted).
   *
   * @return A boolean.
   */
  public static boolean equal(final Line2D l1, final Line2D l2) {
      if (l1 == null) {
          return (l2 == null);
      }
      if (l2 == null) {
          return false;
      }
      if (!l1.getP1().equals(l2.getP1())) {
          return false;
      }
      if (!l1.getP2().equals(l2.getP2())) {
          return false;
      }
      return true;
  }
}



Creates a diagonal cross shape.

   
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
 *
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
 * in the United States and other countries.]
 *
 * -------------------
 * ShapeUtilities.java
 * -------------------
 * (C)opyright 2003-2008, by Object Refinery Limited and Contributors.
 *
 * Original Author:  David Gilbert (for Object Refinery Limited);
 * Contributor(s):   -;
 *
 * $Id: ShapeUtilities.java,v 1.18 2008/06/02 06:58:28 mungady Exp $
 *
 * Changes
 * -------
 * 13-Aug-2003 : Version 1 (DG);
 * 16-Mar-2004 : Moved rotateShape() from RefineryUtilities.java to here (DG);
 * 13-May-2004 : Added new shape creation methods (DG);
 * 30-Sep-2004 : Added createLineRegion() method (DG);
 *               Moved drawRotatedShape() method from RefineryUtilities class
 *               to this class (DG);
 * 04-Oct-2004 : Renamed ShapeUtils --> ShapeUtilities (DG);
 * 26-Oct-2004 : Added a method to test the equality of two Line2D
 *               instances (DG);
 * 10-Nov-2004 : Added new translateShape() and equal(Ellipse2D, Ellipse2D)
 *               methods (DG);
 * 11-Nov-2004 : Renamed translateShape() --> createTranslatedShape() (DG);
 * 07-Jan-2005 : Minor Javadoc fix (DG);
 * 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
 * 21-Jan-2005 : Modified return type of RectangleAnchor.coordinates()
 *               method (DG);
 * 22-Feb-2005 : Added equality tests for Arc2D and GeneralPath (DG);
 * 16-Mar-2005 : Fixed bug where equal(Shape, Shape) fails for two Polygon
 *               instances (DG);
 * 01-Jun-2008 : Fixed bug in equal(GeneralPath, GeneralPath) method (DG);
 *
 */
import java.awt.Shape;
import java.awt.geom.GeneralPath;
/**
 * Utility methods for {@link Shape} objects.
 *
 * @author David Gilbert
 */
public class Main {
  /** A useful constant used internally. */
  private static final float SQRT2 = (float) Math.pow(2.0, 0.5);
  /**
   * Creates a diagonal cross shape.
   *
   * @param l  the length of each "arm".
   * @param t  the thickness.
   *
   * @return A diagonal cross shape.
   */
  public static Shape createDiagonalCross(final float l, final float t) {
      final GeneralPath p0 = new GeneralPath();
      p0.moveTo(-l - t, -l + t);
      p0.lineTo(-l + t, -l - t);
      p0.lineTo(0.0f, -t * SQRT2);
      p0.lineTo(l - t, -l - t);
      p0.lineTo(l + t, -l + t);
      p0.lineTo(t * SQRT2, 0.0f);
      p0.lineTo(l + t, l - t);
      p0.lineTo(l - t, l + t);
      p0.lineTo(0.0f, t * SQRT2);
      p0.lineTo(-l + t, l + t);
      p0.lineTo(-l - t, l - t);
      p0.lineTo(-t * SQRT2, 0.0f);
      p0.closePath();
      return p0;
  }
}



Creates a diamond shape.

   
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
 *
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
 * in the United States and other countries.]
 *
 * -------------------
 * ShapeUtilities.java
 * -------------------
 * (C)opyright 2003-2008, by Object Refinery Limited and Contributors.
 *
 * Original Author:  David Gilbert (for Object Refinery Limited);
 * Contributor(s):   -;
 *
 * $Id: ShapeUtilities.java,v 1.18 2008/06/02 06:58:28 mungady Exp $
 *
 * Changes
 * -------
 * 13-Aug-2003 : Version 1 (DG);
 * 16-Mar-2004 : Moved rotateShape() from RefineryUtilities.java to here (DG);
 * 13-May-2004 : Added new shape creation methods (DG);
 * 30-Sep-2004 : Added createLineRegion() method (DG);
 *               Moved drawRotatedShape() method from RefineryUtilities class
 *               to this class (DG);
 * 04-Oct-2004 : Renamed ShapeUtils --> ShapeUtilities (DG);
 * 26-Oct-2004 : Added a method to test the equality of two Line2D
 *               instances (DG);
 * 10-Nov-2004 : Added new translateShape() and equal(Ellipse2D, Ellipse2D)
 *               methods (DG);
 * 11-Nov-2004 : Renamed translateShape() --> createTranslatedShape() (DG);
 * 07-Jan-2005 : Minor Javadoc fix (DG);
 * 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
 * 21-Jan-2005 : Modified return type of RectangleAnchor.coordinates()
 *               method (DG);
 * 22-Feb-2005 : Added equality tests for Arc2D and GeneralPath (DG);
 * 16-Mar-2005 : Fixed bug where equal(Shape, Shape) fails for two Polygon
 *               instances (DG);
 * 01-Jun-2008 : Fixed bug in equal(GeneralPath, GeneralPath) method (DG);
 *
 */
import java.awt.Shape;
import java.awt.geom.GeneralPath;
/**
 * Utility methods for {@link Shape} objects.
 *
 * @author David Gilbert
 */
public class Main {
  /**
   * Creates a diamond shape.
   *
   * @param s  the size factor (equal to half the height of the diamond).
   *
   * @return A diamond shape.
   */
  public static Shape createDiamond(final float s) {
      final GeneralPath p0 = new GeneralPath();
      p0.moveTo(0.0f, -s);
      p0.lineTo(s, 0.0f);
      p0.lineTo(0.0f, s);
      p0.lineTo(-s, 0.0f);
      p0.closePath();
      return p0;
  }
}



Creates a new Stroke-Object for the given type and with.

   
/**
 * 
 * JFreeReport : a free Java reporting library
 * 
 *
 * Project Info:  http://reporting.pentaho.org/
 *
 * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
 *
 * 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., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
 * in the United States and other countries.]
 *
 * ------------
 * StrokeUtility.java
 * ------------
 * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
 */
import java.awt.BasicStroke;
import java.awt.Stroke;
import java.util.Arrays;
/**
 * This class provides helper methods to work with Strokes and line-styles.
 * 
 * @author Thomas Morgner
 */
public class StrokeUtility {
  /** A constant defining a stroke-type. */
  public static final int STROKE_SOLID = 0;
  /** A constant defining a stroke-type. */
  public static final int STROKE_DASHED = 1;
  /** A constant defining a stroke-type. */
  public static final int STROKE_DOTTED = 2;
  /** A constant defining a stroke-type. */
  public static final int STROKE_DOT_DASH = 3;
  /** A constant defining a stroke-type. */
  public static final int STROKE_DOT_DOT_DASH = 4;
  /** A constant defining a stroke-type. */
  public static final int STROKE_NONE = 5;
  /**
   * Default Constructor. Private to prevent Object-creation.
   */
  private StrokeUtility() {
  }
  /**
   * Creates a new Stroke-Object for the given type and with.
   * 
   * @param type
   *          the stroke-type. (Must be one of the constants defined in this
   *          class.)
   * @param width
   *          the stroke"s width.
   * @return the stroke, never null.
   */
  public static Stroke createStroke(final int type, final float width) {
    final boolean useWidthForStrokes = true;
    final float effectiveWidth;
    if (useWidthForStrokes) {
      effectiveWidth = width;
    } else {
      effectiveWidth = 1;
    }
    switch (type) {
    case STROKE_DASHED:
      return new BasicStroke(width, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10.0f,
          new float[] { 6 * effectiveWidth, 6 * effectiveWidth }, 0.0f);
    case STROKE_DOTTED:
      return new BasicStroke(width, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 5.0f,
          new float[] { 0.0f, 2 * effectiveWidth }, 0.0f);
    case STROKE_DOT_DASH:
      return new BasicStroke(width, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10.0f,
          new float[] { 0, 2 * effectiveWidth, 6 * effectiveWidth, 2 * effectiveWidth }, 0.0f);
    case STROKE_DOT_DOT_DASH:
      return new BasicStroke(width, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10.0f,
          new float[] { 0, 2 * effectiveWidth, 0, 2 * effectiveWidth, 6 * effectiveWidth,
              2 * effectiveWidth }, 0.0f);
    default:
      return new BasicStroke(width);
    }
  }
  /**
   * Tries to extract the stroke-width from the given stroke object.
   * 
   * @param s
   *          the stroke.
   * @return the stroke"s width.
   */
  public static float getStrokeWidth(final Stroke s) {
    if (s instanceof BasicStroke) {
      final BasicStroke bs = (BasicStroke) s;
      return bs.getLineWidth();
    }
    return 1;
  }
  /**
   * Tries to deduct the stroke-type from the given stroke object. This will
   * result in funny return values if the stroke was not created by the
   * {@link #createStroke(int, float)} method.
   * 
   * @param s
   *          the stroke.
   * @return the stroke"s width.
   */
  public static int getStrokeType(final Stroke s) {
    if (s instanceof BasicStroke == false) {
      return STROKE_SOLID;
    }
    final BasicStroke bs = (BasicStroke) s;
    if (bs.getLineWidth() <= 0) {
      return STROKE_NONE;
    }
    final float[] dashes = bs.getDashArray();
    if (dashes == null) {
      return STROKE_SOLID;
    }
    if (dashes.length < 2) {
      return STROKE_SOLID;
    }
    if (dashes.length == 3 || dashes.length == 5) {
      return STROKE_SOLID;
    }
    if (dashes.length == 2) {
      // maybe dashed or dotted ...
      // if (dashes[0] < 2 && dashes[1] < 2) {
      // return STROKE_DOTTED;
      // }
      final float factor = dashes[0] / dashes[1];
      if (factor > 0.9 && factor < 1.1) {
        return STROKE_DASHED;
      } else if (factor < 0.1) {
        return STROKE_DOTTED;
      }
      // else ... not recognized ...
      return STROKE_SOLID;
    } else if (dashes.length == 4) {
      // maybe a dot-dashed stroke ...
      final float[] copyDashes = (float[]) dashes.clone();
      Arrays.sort(copyDashes);
      // the first value should be near zero ..
      if (Math.abs(copyDashes[0] / bs.getLineWidth()) > 0.5) {
        // not recognized ..
        return STROKE_SOLID;
      }
      // test that the first two values have the same size
      final float factor1 = (2 * bs.getLineWidth()) / copyDashes[1];
      final float factor2 = (2 * bs.getLineWidth()) / copyDashes[2];
      final float factorBig = (2 * bs.getLineWidth()) / copyDashes[3];
      if ((factor1 < 0.9 || factor1 > 1.1) || (factor2 < 0.9 || factor2 > 1.1)) {
        // not recognized ...
        return STROKE_SOLID;
      }
      if (factorBig < 0.4 || factorBig > 2.5) {
        return STROKE_DOT_DASH;
      }
      if (factorBig < 0.9 || factorBig > 1.1) {
        return STROKE_DOTTED;
      }
      return STROKE_DASHED;
    } else if (dashes.length == 6) {
      // maybe a dot-dashed stroke ...
      final float[] copyDashes = (float[]) dashes.clone();
      Arrays.sort(copyDashes);
      // test that the first three values have the same size
      // the first two values should be near zero ..
      if (Math.abs(copyDashes[0] / bs.getLineWidth()) > 0.5) {
        // not recognized ..
        return STROKE_SOLID;
      }
      if (Math.abs(copyDashes[1] / bs.getLineWidth()) > 0.5) {
        // not recognized ..
        return STROKE_SOLID;
      }
      final float factor2 = (2 * bs.getLineWidth()) / copyDashes[2];
      final float factor3 = (2 * bs.getLineWidth()) / copyDashes[3];
      final float factor4 = (2 * bs.getLineWidth()) / copyDashes[4];
      final float factorBig = (2 * bs.getLineWidth()) / copyDashes[5];
      if ((factor2 < 0.9 || factor2 > 1.1) || (factor3 < 0.9 || factor3 > 1.1)
          || (factor4 < 0.9 || factor4 > 1.1)) {
        return STROKE_SOLID;
      }
      if (factorBig < 0.4 || factorBig > 2.5) {
        return STROKE_DOT_DOT_DASH;
      }
      if ((factorBig < 0.9 || factorBig > 1.1)) {
        return STROKE_DOTTED;
      }
      return STROKE_DASHED;
    }
    // not recognized ...
    return STROKE_SOLID;
  }
}



Creates a region surrounding a line segment by "widening" the line segment.

   
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
 *
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
 * in the United States and other countries.]
 *
 * -------------------
 * ShapeUtilities.java
 * -------------------
 * (C)opyright 2003-2008, by Object Refinery Limited and Contributors.
 *
 * Original Author:  David Gilbert (for Object Refinery Limited);
 * Contributor(s):   -;
 *
 * $Id: ShapeUtilities.java,v 1.18 2008/06/02 06:58:28 mungady Exp $
 *
 * Changes
 * -------
 * 13-Aug-2003 : Version 1 (DG);
 * 16-Mar-2004 : Moved rotateShape() from RefineryUtilities.java to here (DG);
 * 13-May-2004 : Added new shape creation methods (DG);
 * 30-Sep-2004 : Added createLineRegion() method (DG);
 *               Moved drawRotatedShape() method from RefineryUtilities class
 *               to this class (DG);
 * 04-Oct-2004 : Renamed ShapeUtils --> ShapeUtilities (DG);
 * 26-Oct-2004 : Added a method to test the equality of two Line2D
 *               instances (DG);
 * 10-Nov-2004 : Added new translateShape() and equal(Ellipse2D, Ellipse2D)
 *               methods (DG);
 * 11-Nov-2004 : Renamed translateShape() --> createTranslatedShape() (DG);
 * 07-Jan-2005 : Minor Javadoc fix (DG);
 * 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
 * 21-Jan-2005 : Modified return type of RectangleAnchor.coordinates()
 *               method (DG);
 * 22-Feb-2005 : Added equality tests for Arc2D and GeneralPath (DG);
 * 16-Mar-2005 : Fixed bug where equal(Shape, Shape) fails for two Polygon
 *               instances (DG);
 * 01-Jun-2008 : Fixed bug in equal(GeneralPath, GeneralPath) method (DG);
 *
 */
import java.awt.Shape;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
/**
 * Utility methods for {@link Shape} objects.
 *
 * @author David Gilbert
 */
public class Main {

  /**
   * Creates a region surrounding a line segment by "widening" the line
   * segment.  A typical use for this method is the creation of a
   * "clickable" region for a line that is displayed on-screen.
   *
   * @param line  the line (<code>null</code> not permitted).
   * @param width  the width of the region.
   *
   * @return A region that surrounds the line.
   */
  public static Shape createLineRegion(final Line2D line, final float width) {
      final GeneralPath result = new GeneralPath();
      final float x1 = (float) line.getX1();
      final float x2 = (float) line.getX2();
      final float y1 = (float) line.getY1();
      final float y2 = (float) line.getY2();
      if ((x2 - x1) != 0.0) {
          final double theta = Math.atan((y2 - y1) / (x2 - x1));
          final float dx = (float) Math.sin(theta) * width;
          final float dy = (float) Math.cos(theta) * width;
          result.moveTo(x1 - dx, y1 + dy);
          result.lineTo(x1 + dx, y1 - dy);
          result.lineTo(x2 + dx, y2 - dy);
          result.lineTo(x2 - dx, y2 + dy);
          result.closePath();
      }
      else {
          // special case, vertical line
          result.moveTo(x1 - width / 2.0f, y1);
          result.lineTo(x1 + width / 2.0f, y1);
          result.lineTo(x2 + width / 2.0f, y2);
          result.lineTo(x2 - width / 2.0f, y2);
          result.closePath();
      }
      return result;
  }
}



Creates a triangle shape that points downwards.

   
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
 *
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
 * in the United States and other countries.]
 *
 * -------------------
 * ShapeUtilities.java
 * -------------------
 * (C)opyright 2003-2008, by Object Refinery Limited and Contributors.
 *
 * Original Author:  David Gilbert (for Object Refinery Limited);
 * Contributor(s):   -;
 *
 * $Id: ShapeUtilities.java,v 1.18 2008/06/02 06:58:28 mungady Exp $
 *
 * Changes
 * -------
 * 13-Aug-2003 : Version 1 (DG);
 * 16-Mar-2004 : Moved rotateShape() from RefineryUtilities.java to here (DG);
 * 13-May-2004 : Added new shape creation methods (DG);
 * 30-Sep-2004 : Added createLineRegion() method (DG);
 *               Moved drawRotatedShape() method from RefineryUtilities class
 *               to this class (DG);
 * 04-Oct-2004 : Renamed ShapeUtils --> ShapeUtilities (DG);
 * 26-Oct-2004 : Added a method to test the equality of two Line2D
 *               instances (DG);
 * 10-Nov-2004 : Added new translateShape() and equal(Ellipse2D, Ellipse2D)
 *               methods (DG);
 * 11-Nov-2004 : Renamed translateShape() --> createTranslatedShape() (DG);
 * 07-Jan-2005 : Minor Javadoc fix (DG);
 * 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
 * 21-Jan-2005 : Modified return type of RectangleAnchor.coordinates()
 *               method (DG);
 * 22-Feb-2005 : Added equality tests for Arc2D and GeneralPath (DG);
 * 16-Mar-2005 : Fixed bug where equal(Shape, Shape) fails for two Polygon
 *               instances (DG);
 * 01-Jun-2008 : Fixed bug in equal(GeneralPath, GeneralPath) method (DG);
 *
 */
import java.awt.Shape;
import java.awt.geom.GeneralPath;
/**
 * Utility methods for {@link Shape} objects.
 *
 * @author David Gilbert
 */
public class Main {

  /**
   * Creates a triangle shape that points downwards.
   *
   * @param s  the size factor (equal to half the height of the triangle).
   *
   * @return A triangle shape.
   */
  public static Shape createDownTriangle(final float s) {
      final GeneralPath p0 = new GeneralPath();
      p0.moveTo(0.0f, s);
      p0.lineTo(s, -s);
      p0.lineTo(-s, -s);
      p0.closePath();
      return p0;
  }
}



Creates a triangle shape that points upwards.

   
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
 *
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
 * in the United States and other countries.]
 *
 * -------------------
 * ShapeUtilities.java
 * -------------------
 * (C)opyright 2003-2008, by Object Refinery Limited and Contributors.
 *
 * Original Author:  David Gilbert (for Object Refinery Limited);
 * Contributor(s):   -;
 *
 * $Id: ShapeUtilities.java,v 1.18 2008/06/02 06:58:28 mungady Exp $
 *
 * Changes
 * -------
 * 13-Aug-2003 : Version 1 (DG);
 * 16-Mar-2004 : Moved rotateShape() from RefineryUtilities.java to here (DG);
 * 13-May-2004 : Added new shape creation methods (DG);
 * 30-Sep-2004 : Added createLineRegion() method (DG);
 *               Moved drawRotatedShape() method from RefineryUtilities class
 *               to this class (DG);
 * 04-Oct-2004 : Renamed ShapeUtils --> ShapeUtilities (DG);
 * 26-Oct-2004 : Added a method to test the equality of two Line2D
 *               instances (DG);
 * 10-Nov-2004 : Added new translateShape() and equal(Ellipse2D, Ellipse2D)
 *               methods (DG);
 * 11-Nov-2004 : Renamed translateShape() --> createTranslatedShape() (DG);
 * 07-Jan-2005 : Minor Javadoc fix (DG);
 * 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
 * 21-Jan-2005 : Modified return type of RectangleAnchor.coordinates()
 *               method (DG);
 * 22-Feb-2005 : Added equality tests for Arc2D and GeneralPath (DG);
 * 16-Mar-2005 : Fixed bug where equal(Shape, Shape) fails for two Polygon
 *               instances (DG);
 * 01-Jun-2008 : Fixed bug in equal(GeneralPath, GeneralPath) method (DG);
 *
 */
import java.awt.Shape;
import java.awt.geom.GeneralPath;
/**
 * Utility methods for {@link Shape} objects.
 *
 * @author David Gilbert
 */
public class Main {
  /**
   * Creates a triangle shape that points upwards.
   *
   * @param s  the size factor (equal to half the height of the triangle).
   *
   * @return A triangle shape.
   */
  public static Shape createUpTriangle(final float s) {
      final GeneralPath p0 = new GeneralPath();
      p0.moveTo(0.0f, -s);
      p0.lineTo(s, s);
      p0.lineTo(-s, s);
      p0.closePath();
      return p0;
  }
}



Creating a Shape Using Lines and Curves

     
import java.awt.geom.GeneralPath;
public class BasicShapes {
  public static void main(String[] args) {
    GeneralPath shape = new GeneralPath();
    shape.moveTo(1, 1);
    shape.lineTo(2, 2);
    shape.quadTo(3, 3, 4, 4);
    shape.curveTo(5, 5, 6, 6, 7, 7);
    shape.closePath();
  }
}



Creating Basic Shapes

     
import java.awt.Shape;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
public class BasicShapes {
  public static void main(String[] args) {
    int x1 = 1, x2 = 2, w = 3, h = 4, x = 5, y = 6, y1 = 1, y2 = 2, start = 3;
    Shape line = new Line2D.Float(x1, y1, x2, y2);
    Shape arc = new Arc2D.Float(x, y, w, h, start, 1, 1);
    Shape oval = new Ellipse2D.Float(x, y, w, h);
    Shape rectangle = new Rectangle2D.Float(x, y, w, h);
    Shape roundRectangle = new RoundRectangle2D.Float(x, y, w, h, 1, 2);
  }
}



Draw an oval outline

      
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MainClass extends JPanel {
  public static void main(String[] a) {
    JFrame f = new JFrame();
    f.setSize(400, 400);
    f.add(new MainClass());
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setVisible(true);
  }
  public void paint(Graphics g) {
    g.setColor (Color.yellow);  
    g.drawOval (5, 15, 50, 75);   
  }
}



Draw a Polygon

     
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DrawPolyPanel extends JPanel {
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Polygon p = new Polygon();
    for (int i = 0; i < 5; i++)
      p.addPoint((int) (100 + 50 * Math.cos(i * 2 * Math.PI / 5)),
          (int) (100 + 50 * Math.sin(i * 2 * Math.PI / 5)));
    g.drawPolygon(p);
    Polygon s = new Polygon();
    for (int i = 0; i < 360; i++) {
      double t = i / 360.0;
      s.addPoint((int) (150 + 50 * t * Math.cos(8 * t * Math.PI)),
          (int) (150 + 50 * t * Math.sin(8 * t * Math.PI)));
    }
    g.drawPolygon(s);
  }
  public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setTitle("DrawPoly");
    frame.setSize(350, 250);
    frame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    Container contentPane = frame.getContentPane();
    contentPane.add(new DrawPolyPanel());
    frame.show();
  }
}



Draw Arc

     
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JApplet;
import javax.swing.JFrame;
public class ArcDemo2D extends JApplet {
  final static BasicStroke wideStroke = new BasicStroke(8.0f);  
  public void init() {
    setBackground(Color.white);
    setForeground(Color.white);
  }

  public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setPaint(Color.gray);
    int x = 5;
    int y = 7;
    g2.setStroke(wideStroke);
    g2.draw(new Arc2D.Double(x, y, 200, 200, 90, 135,
        Arc2D.OPEN));
    g2.drawString("Arc2D", x, 250);
  }
  public static void main(String s[]) {
    JFrame f = new JFrame("");
    f.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    JApplet applet = new ArcDemo2D();
    f.getContentPane().add("Center", applet);
    applet.init();
    f.pack();
    f.setSize(new Dimension(300, 300));
    f.show();
  }
}



Draw a (Round)rectangle

     
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DrawRectPanel extends JPanel {
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.setColor(Color.blue);
    g.drawRect(10, 10, 80, 30);
    g.drawRoundRect(100, 10, 80, 30, 15, 15);
    int thickness = 4;
    for (int i = 0; i <= thickness; i++)
      g.draw3DRect(200 - i, 10 - i, 80 + 2 * i, 30 + 2 * i, true);
    for (int i = 0; i < thickness; i++)
      g.draw3DRect(200 - i, 50 - i, 80 + 2 * i, 30 + 2 * i, false);
    g.drawOval(10, 100, 80, 30);
  }
  public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setTitle("DrawRect");
    frame.setSize(300, 200);
    frame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    Container contentPane = frame.getContentPane();
    contentPane.add(new DrawRectPanel());
    frame.show();
  }
}



Draw Ellipse

     
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JApplet;
import javax.swing.JFrame;
public class EllipseDemo2D extends JApplet {
  final static BasicStroke stroke = new BasicStroke(2.0f);  
  public void init() {
    setBackground(Color.white);
    setForeground(Color.white);
  }

  public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setPaint(Color.gray);
    int x = 5;
    int y = 7;
    g2.setStroke(stroke);
    g2.draw(new Ellipse2D.Double(x, y, 200, 200));
    g2.drawString("Ellipse2D", x, 250);
  }
  public static void main(String s[]) {
    JFrame f = new JFrame("");
    f.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    JApplet applet = new EllipseDemo2D();
    f.getContentPane().add("Center", applet);
    applet.init();
    f.pack();
    f.setSize(new Dimension(300, 300));
    f.show();
  }
}



Draw line

     
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JApplet;
import javax.swing.JFrame;
public class LineDemo2D extends JApplet {
  public void init() {
    setBackground(Color.white);
    setForeground(Color.white);
  }

  public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setPaint(Color.gray);
    int x = 5;
    int y = 7;
    g2.draw(new Line2D.Double(x, y, 200, 200));
    g2.drawString("Line2D", x, 250);
  }
  public static void main(String s[]) {
    JFrame f = new JFrame("ShapesDemo2D");
    f.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    JApplet applet = new LineDemo2D();
    f.getContentPane().add("Center", applet);
    applet.init();
    f.pack();
    f.setSize(new Dimension(300, 300));
    f.show();
  }
}



Draw rectangle 2

     
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JApplet;
import javax.swing.JFrame;
public class RectangleDemo2D extends JApplet {
  final static BasicStroke stroke = new BasicStroke(2.0f);
  public void init() {
    setBackground(Color.white);
    setForeground(Color.white);
  }

  public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setPaint(Color.gray);
    int x = 5;
    int y = 7;
    g2.setStroke(stroke);
    g2.draw(new Rectangle2D.Double(x, y, 200, 200));
    g2.drawString("Rectangle2D", x, 250);
    
    
  }
  public static void main(String s[]) {
    JFrame f = new JFrame("");
    f.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    JApplet applet = new RectangleDemo2D();
    f.getContentPane().add("Center", applet);
    applet.init();
    f.pack();
    f.setSize(new Dimension(300, 300));
    f.show();
  }
}



Draw rectangles, use the drawRect() method. To fill rectangles, use the fillRect() method

     
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Rectangles extends JPanel {
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g;
    g2d.setColor(new Color(212, 212, 212));
    g2d.drawRect(10, 15, 90, 60);

    g2d.setColor(new Color(31, 21, 1));
    g2d.fillRect(250, 195, 90, 60);
  }
  public static void main(String[] args) {
    Rectangles rects = new Rectangles();
    JFrame frame = new JFrame("Rectangles");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(rects);
    frame.setSize(360, 300);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }
}



Draws a shape with the specified rotation about (x, y).

   
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
 *
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
 * in the United States and other countries.]
 *
 * -------------------
 * ShapeUtilities.java
 * -------------------
 * (C)opyright 2003-2008, by Object Refinery Limited and Contributors.
 *
 * Original Author:  David Gilbert (for Object Refinery Limited);
 * Contributor(s):   -;
 *
 * $Id: ShapeUtilities.java,v 1.18 2008/06/02 06:58:28 mungady Exp $
 *
 * Changes
 * -------
 * 13-Aug-2003 : Version 1 (DG);
 * 16-Mar-2004 : Moved rotateShape() from RefineryUtilities.java to here (DG);
 * 13-May-2004 : Added new shape creation methods (DG);
 * 30-Sep-2004 : Added createLineRegion() method (DG);
 *               Moved drawRotatedShape() method from RefineryUtilities class
 *               to this class (DG);
 * 04-Oct-2004 : Renamed ShapeUtils --> ShapeUtilities (DG);
 * 26-Oct-2004 : Added a method to test the equality of two Line2D
 *               instances (DG);
 * 10-Nov-2004 : Added new translateShape() and equal(Ellipse2D, Ellipse2D)
 *               methods (DG);
 * 11-Nov-2004 : Renamed translateShape() --> createTranslatedShape() (DG);
 * 07-Jan-2005 : Minor Javadoc fix (DG);
 * 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
 * 21-Jan-2005 : Modified return type of RectangleAnchor.coordinates()
 *               method (DG);
 * 22-Feb-2005 : Added equality tests for Arc2D and GeneralPath (DG);
 * 16-Mar-2005 : Fixed bug where equal(Shape, Shape) fails for two Polygon
 *               instances (DG);
 * 01-Jun-2008 : Fixed bug in equal(GeneralPath, GeneralPath) method (DG);
 *
 */
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
/**
 * Utility methods for {@link Shape} objects.
 *
 * @author David Gilbert
 */
public class Main {

  /**
   * Draws a shape with the specified rotation about <code>(x, y)</code>.
   *
   * @param g2  the graphics device (<code>null</code> not permitted).
   * @param shape  the shape (<code>null</code> not permitted).
   * @param angle  the angle (in radians).
   * @param x  the x coordinate for the rotation point.
   * @param y  the y coordinate for the rotation point.
   */
  public static void drawRotatedShape(final Graphics2D g2, final Shape shape,
                                      final double angle,
                                      final float x, final float y) {
      final AffineTransform saved = g2.getTransform();
      final AffineTransform rotate = AffineTransform.getRotateInstance(
              angle, x, y);
      g2.transform(rotate);
      g2.draw(shape);
      g2.setTransform(saved);
  }
}



Draw text

     
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DrawSimpleText extends JPanel{
    public void paint(Graphics g) {
        Graphics2D g2 = (Graphics2D)g;
        
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
        Font font = new Font("Serif", Font.PLAIN, 96);
        g2.setFont(font);
        g2.drawString("Java Source and Support", 40, 120); 
      }
  public static void main(String[] args) {
    JFrame f = new JFrame();
    f.getContentPane().add(new DrawSimpleText());
    f.setSize(300, 200);
    f.setVisible(true);
  }
}



Draw unicode string

     
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
public class UnicodeText {
  public static void main(String[] args) {
    JFrame f = new JFrame() {
      public void paint(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
        Font font = new Font("Lucida Sans Regular", Font.PLAIN, 32);
        g2.setFont(font);
        g2.drawString("\u032e\u0624\u0639", 40, 80);
      }
    };
    f.setSize(200,200);
    f.setVisible(true);
  }
}



Effects

     
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.ruponent;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import javax.swing.JFrame;
import com.sun.image.codec.jpeg.ImageFormatException;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageDecoder;
public class ShowOff extends Component {
  public static void main(String[] args) {
    try {
      String filename = "largejexpLogo.jpg";
      String message = "Java Source and Support";
      int split = 4;
      JFrame f = new JFrame();
      f.getContentPane().setLayout(new BorderLayout());
      ShowOff showOff = new ShowOff(filename, message, split);
      f.add(showOff, BorderLayout.CENTER);
      f.setSize(f.getPreferredSize());
      f.setResizable(false);
      f.setVisible(true);
    } catch (Exception e) {
      System.out.println(e);
      System.exit(0);
    }
  }
  private BufferedImage mImage;
  private Font mFont;
  private String mMessage;
  private int mSplit;
  private TextLayout mLayout;
  public ShowOff(String filename, String message, int split)
      throws IOException, ImageFormatException {
    InputStream in = getClass().getResourceAsStream(filename);
    JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(in);
    mImage = decoder.decodeAsBufferedImage();
    in.close();
    mFont = new Font("Serif", Font.PLAIN, 116);
    mMessage = message;
    mSplit = split;
    setSize((int) mImage.getWidth(), (int) mImage.getHeight());
  }
  public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    drawBackground(g2);
    drawImageMosaic(g2);
    drawText(g2);
  }
  protected void drawBackground(Graphics2D g2) {
    int side = 45;
    int width = getSize().width;
    int height = getSize().height;
    Color[] colors = { Color.yellow, Color.cyan, Color.orange, Color.pink,
        Color.magenta, Color.lightGray };
    for (int y = 0; y < height; y += side) {
      for (int x = 0; x < width; x += side) {
        Ellipse2D ellipse = new Ellipse2D.Float(x, y, side, side);
        int index = (x + y) / side % colors.length;
        g2.setPaint(colors[index]);
        g2.fill(ellipse);
      }
    }
  }
  protected void drawImageMosaic(Graphics2D g2) {
    int side = 36;
    int width = mImage.getWidth();
    int height = mImage.getHeight();
    for (int y = 0; y < height; y += side) {
      for (int x = 0; x < width; x += side) {
        float xBias = (float) x / (float) width;
        float yBias = (float) y / (float) height;
        float alpha = 1.0f - Math.abs(xBias - yBias);
        g2.setComposite(AlphaComposite.getInstance(
            AlphaComposite.SRC_OVER, alpha));
        int w = Math.min(side, width - x);
        int h = Math.min(side, height - y);
        BufferedImage tile = mImage.getSubimage(x, y, w, h);
        g2.drawImage(tile, x, y, null);
      }
    }
    g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
  }
  protected void drawText(Graphics2D g2) {
    FontRenderContext frc = g2.getFontRenderContext();
    mLayout = new TextLayout(mMessage, mFont, frc);
    int width = getSize().width;
    int height = getSize().height;
    Rectangle2D bounds = mLayout.getBounds();
    double x = (width - bounds.getWidth()) / 2;
    double y = height - bounds.getHeight();
    drawString(g2, x, y, 0);
    drawString(g2, width - bounds.getHeight(), y, -Math.PI / 2);
  }
  protected void drawString(Graphics2D g2, double x, double y, double theta) {
    g2.translate(x, y);
    g2.rotate(theta);
    String first = mMessage.substring(0, mSplit);
    float width = drawBoxedString(g2, first, Color.white, Color.red, 0);
    String second = mMessage.substring(mSplit);
    drawBoxedString(g2, second, Color.blue, Color.white, width);
    g2.rotate(-theta);
    g2.translate(-x, -y);
  }
  protected float drawBoxedString(Graphics2D g2, String s, Color c1,
      Color c2, double x) {
    FontRenderContext frc = g2.getFontRenderContext();
    TextLayout subLayout = new TextLayout(s, mFont, frc);
    float advance = subLayout.getAdvance();
    GradientPaint gradient = new GradientPaint((float) x, 0, c1,
        (float) (x + advance), 0, c2);
    g2.setPaint(gradient);
    Rectangle2D bounds = mLayout.getBounds();
    Rectangle2D back = new Rectangle2D.Double(x, 0, advance, bounds
        .getHeight());
    g2.fill(back);
    g2.setPaint(Color.white);
    g2.setFont(mFont);
    g2.drawString(s, (float) x, (float) -bounds.getY());
    return advance;
  }
}



Fill a polygon

     
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class FillPolyPanel extends JPanel {
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    int radius = 40;
    int centerX = 50;
    int centerY = 100;
    int angle = 30; 
    int dx = (int) (radius * Math.cos(angle * Math.PI / 180));
    int dy = (int) (radius * Math.sin(angle * Math.PI / 180));
    g.fillArc(centerX - radius, centerY - radius, 2 * radius, 2 * radius, angle, 360 - 2 * angle);
    Polygon p = new Polygon();
    centerX = 150;
    for (int i = 0; i < 5; i++)
      p.addPoint((int) (centerX + radius * Math.cos(i * 2 * Math.PI / 5)),
          (int) (centerY + radius * Math.sin(i * 2 * Math.PI / 5)));
    g.fillPolygon(p);
    p = new Polygon();
    centerX = 250;
    for (int i = 0; i < 360; i++) {
      double t = i / 360.0;
      p.addPoint((int) (centerX + radius * t * Math.cos(8 * t * Math.PI)),
          (int) (centerY + radius * t * Math.sin(8 * t * Math.PI)));
    }
    g.fillPolygon(p);
  }
  public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setTitle("FillPoly");
    frame.setSize(300, 200);
    frame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    Container contentPane = frame.getContentPane();
    contentPane.add(new FillPolyPanel());
    frame.show();
  }
}



Fill Arc 2

     
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JApplet;
import javax.swing.JFrame;
public class FilledArc extends JApplet {
  public void init() {
    setBackground(Color.white);
    setForeground(Color.white);
  }
  public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    int x = 5;
    int y = 7;
    // fill Arc2D
    g2.setPaint(Color.red);
    g2.fill(new Arc2D.Double(x, y, 200, 200, 90, 135, Arc2D.OPEN));
    g2.setPaint(Color.black);
    g2.drawString("Filled Arc2D", x, 250);
  }
  public static void main(String s[]) {
    JFrame f = new JFrame("");
    f.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    JApplet applet = new FilledArc();
    f.getContentPane().add("Center", applet);
    applet.init();
    f.pack();
    f.setSize(new Dimension(300, 300));
    f.show();
  }
}



Fill a Rectangle 2

     
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JApplet;
import javax.swing.JFrame;
public class FilledRectangleDemo2D extends JApplet {
  public void init() {
    setBackground(Color.white);
    setForeground(Color.white);
  }
  public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setPaint(Color.gray);
    int x = 5;
    int y = 7;
    g2.setPaint(Color.red);
    g2.fill(new Rectangle2D.Double(x, y, 200, 200));
    g2.setPaint(Color.black);
    g2.drawString("Filled Rectangle2D", x, 250);
  }
  public static void main(String s[]) {
    JFrame f = new JFrame("");
    f.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    JApplet applet = new FilledRectangleDemo2D();
    f.getContentPane().add("Center", applet);
    applet.init();
    f.pack();
    f.setSize(new Dimension(300, 300));
    f.show();
  }
}



Fill a (Round)rectangle

     
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class FillRectPanel extends JPanel {
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.drawRect(10, 10, 80, 30);
    g.drawRoundRect(100, 10, 80, 30, 15, 15);
    g.drawOval(10, 100, 80, 30);
    g.setColor(Color.red);
    g.fillRect(10, 10, 80, 30);
    g.fillRoundRect(100, 10, 80, 30, 15, 15);
    int thickness = 4;
    g.fill3DRect(200, 10, 80, 30, true);
    for (int i = 1; i <= thickness; i++)
      g.draw3DRect(200 - i, 10 - i, 80 + 2 * i - 1, 30 + 2 * i - 1, true);
    g.fill3DRect(200, 50, 80, 30, false);
    for (int i = 1; i <= thickness; i++)
      g.draw3DRect(200 - i, 50 - i, 80 + 2 * i - 1, 30 + 2 * i - 1, true);
    g.fillOval(10, 100, 80, 30);
  }
  public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setTitle("FillRect");
    frame.setSize(300, 200);
    frame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    Container contentPane = frame.getContentPane();
    contentPane.add(new FillRectPanel());
    frame.show();
  }
}



Fill a solid oval

      
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MainClass extends JPanel {
  public static void main(String[] a) {
    JFrame f = new JFrame();
    f.setSize(400, 400);
    f.add(new MainClass());
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setVisible(true);
  }
  public void paint(Graphics g) {
    g.setColor (Color.yellow);  
    g.fillOval (5, 15, 50, 75);    
  }
}



fillRect (int, int, int, int) method draws a solid rectangle

      
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MainClass extends JPanel {
  public static void main(String[] a) {
    JFrame f = new JFrame();
    f.setSize(400, 400);
    f.add(new MainClass());
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setVisible(true);
  }
  public void paint(Graphics g) {
    g.fillRect (5, 15, 50, 75);   
  }
}



Generate Polygon

   
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
/*
 * $Id: ShapeUtils.java,v 1.4 2008/10/14 22:31:46 rah003 Exp $
 *
 * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * 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
 */
public class Utils {
  public static Shape generatePolygon(int sides, int outsideRadius, boolean normalize) {
    return generatePolygon(sides, outsideRadius, 0, normalize);
  }
  public static Shape generatePolygon(int sides, int outsideRadius, int insideRadius,
      boolean normalize) {
    Shape shape = generatePolygon(sides, outsideRadius, insideRadius);
    if (normalize) {
      Rectangle2D bounds = shape.getBounds2D();
      GeneralPath path = new GeneralPath(shape);
      shape = path.createTransformedShape(AffineTransform.getTranslateInstance(-bounds.getX(),
          -bounds.getY()));
    }
    return shape;
  }
  public static Shape generatePolygon(int sides, int outsideRadius, int insideRadius) {
    if (sides < 3) {
      return new Ellipse2D.Float(0, 0, 10, 10);
    }
    AffineTransform trans = new AffineTransform();
    Polygon poly = new Polygon();
    for (int i = 0; i < sides; i++) {
      trans.rotate(Math.PI * 2 / (float) sides / 2);
      Point2D out = trans.transform(new Point2D.Float(0, outsideRadius), null);
      poly.addPoint((int) out.getX(), (int) out.getY());
      trans.rotate(Math.PI * 2 / (float) sides / 2);
      if (insideRadius > 0) {
        Point2D in = trans.transform(new Point2D.Float(0, insideRadius), null);
        poly.addPoint((int) in.getX(), (int) in.getY());
      }
    }
    return poly;
  }
}



GlyphVector.getNumGlyphs()

     
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class RotatedText extends JPanel {
  public void paint(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    String s = "111111111111111111111111111111";
    Font font = new Font("Courier", Font.PLAIN, 12);
    g2d.translate(20, 20);
    FontRenderContext frc = g2d.getFontRenderContext();
    GlyphVector gv = font.createGlyphVector(frc, s);
    int length = gv.getNumGlyphs();
    System.out.println(length);
  }
  public static void main(String[] args) {
    JFrame frame = new JFrame("Rotated text");
    frame.add(new RotatedText());
    frame.setSize(400, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }
}



Hypnosis Spiral

     
/*
 * 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.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;
/**
 * A Swing component that smoothly animates a spiral in a hypnotic way.
 */
public class Hypnosis extends JComponent implements ActionListener {
  double x, y; // The center of the spiral
  double r1, r2; // The inner and outer radii of the spiral
  double a1, a2; // The start and end angles of the spiral
  double deltaA; // How much the angle changes each frame
  double deltaX, deltaY; // The trajectory of the center
  float linewidth; // How wide the lines are
  Timer timer; // The object that triggers the animation
  BufferedImage buffer; // The image we use for double-buffering
  Graphics2D osg; // Graphics2D object for drawing into the buffer
  public Hypnosis(double x, double y, double r1, double r2, double a1,
      double a2, float linewidth, int delay, double deltaA,
      double deltaX, double deltaY) {
    this.x = x;
    this.y = y;
    this.r1 = r1;
    this.r2 = r2;
    this.a1 = a1;
    this.a2 = a2;
    this.linewidth = linewidth;
    this.deltaA = deltaA;
    this.deltaX = deltaX;
    this.deltaY = deltaY;
    // Set up a timer to call actionPerformed() every delay milliseconds
    timer = new Timer(delay, this);
    // Create a buffer for double-buffering
    buffer = new BufferedImage((int) (2 * r2 + linewidth),
        (int) (2 * r2 + linewidth), BufferedImage.TYPE_INT_RGB);
    // Create a Graphics object for the buffer, and set the linewidth
    // and request antialiasing when drawing with it
    osg = buffer.createGraphics();
    osg.setStroke(new BasicStroke(linewidth, BasicStroke.CAP_ROUND,
        BasicStroke.JOIN_ROUND));
    osg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
  }
  // Start and stop the animation by starting and stopping the timer
  public void start() {
    timer.start();
  }
  public void stop() {
    timer.stop();
  }
  /**
   * Swing calls this method to ask the component to redraw itself. This
   * method uses double-buffering to make the animation smoother. Swing does
   * double-buffering automatically, so this may not actually make much
   * difference, but it is important to understand the technique.
   */
  public void paintComponent(Graphics g) {
    // Clear the background of the off-screen image
    osg.setColor(getBackground());
    osg.fillRect(0, 0, buffer.getWidth(), buffer.getHeight());
    // Now draw a black spiral into the off-screen image
    osg.setColor(Color.black);
    osg.draw(new Spiral(r2 + linewidth / 2, r2 + linewidth / 2, r1, a1, r2,
        a2));
    // Now copy that off-screen image onto the screen
    g.drawImage(buffer, (int) (x - r2), (int) (y - r2), this);
  }
  /**
   * This method implements the ActionListener interface. Our Timer object
   * calls this method periodically. It updates the position and angles of the
   * spiral and requests a redraw. Instead of redrawing the entire component,
   * however, this method requests a redraw only for the area that has
   * changed.
   */
  public void actionPerformed(ActionEvent e) {
    // Ask to have the old bounding box of the spiral redrawn.
    // Nothing else has anything drawn in it, so it doesn"t need a redraw
    repaint((int) (x - r2 - linewidth), (int) (y - r2 - linewidth),
        (int) (2 * (r2 + linewidth)), (int) (2 * (r2 + linewidth)));
    // Now animate: update the position and angles of the spiral
    // Bounce if we"ve hit an edge
    Rectangle bounds = getBounds();
    if ((x - r2 + deltaX < 0) || (x + r2 + deltaX > bounds.width))
      deltaX = -deltaX;
    if ((y - r2 + deltaY < 0) || (y + r2 + deltaY > bounds.height))
      deltaY = -deltaY;
    // Move the center of the spiral
    x += deltaX;
    y += deltaY;
    // Increment the start and end angles;
    a1 += deltaA;
    a2 += deltaA;
    if (a1 > 2 * Math.PI) { // Don"t let them get too big
      a1 -= 2 * Math.PI;
      a2 -= 2 * Math.PI;
    }
    // Now ask to have the new bounding box of the spiral redrawn. This
    // rectangle will be intersected with the redraw rectangle requested
    // above, and only the combined region will be redrawn
    repaint((int) (x - r2 - linewidth), (int) (y - r2 - linewidth),
        (int) (2 * (r2 + linewidth)), (int) (2 * (r2 + linewidth)));
  }
  /** Tell Swing not to double-buffer for us, since we do our own */
  public boolean isDoubleBuffered() {
    return false;
  }
  /** This is a main() method for testing the component */
  public static void main(String[] args) {
    JFrame f = new JFrame("Hypnosis");
    Hypnosis h = new Hypnosis(200, 200, 10, 100, 0, 11 * Math.PI, 7, 100,
        2 * Math.PI / 30, 3, 5);
    f.getContentPane().add(h, BorderLayout.CENTER);
    f.setSize(400, 400);
    f.show();
    h.start();
  }
}



Mouse drag and drop to draw

     
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;
public class Ellipse extends JFrame {
  DrawingCanvas canvas;
  JLabel location;
  public Ellipse() {
    super();
    Container container = getContentPane();
    canvas = new DrawingCanvas();
    container.add(canvas);
    JPanel panel = new JPanel();
    panel.setLayout(new GridLayout(1, 2));
    panel.add(new JLabel("x,y: ", JLabel.RIGHT));
    location = new JLabel("");
    panel.add(location);
    container.add(panel, BorderLayout.SOUTH);
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    setSize(600,300);
    setVisible(true);
  }
    public static void main(String arg[]) {
    new Ellipse();
  }
  class DrawingCanvas extends JPanel {
    double x, y, w, h;
    int x1, y1, x2, y2;
    Ellipse2D ellipse;
    Ellipse2D selectedShape;
    Rectangle2D boundingRec;
    Cursor curCursor;
    public DrawingCanvas() {
      x = 20;
      y = 20;
      w = 100;
      h = 75;
      setBackground(Color.white);
      addMouseListener(new MyMouseListener());
      addMouseMotionListener(new MyMouseMotionListener());
    }
    public void paint(Graphics g) {
      Graphics2D g2D = (Graphics2D) g;
      ellipse = new Ellipse2D.Double(x, y, w, h);
      g2D.draw(ellipse);
      if (boundingRec != null) {
        drawHighlightSquares(g2D, boundingRec);
      }
      if (curCursor != null)
        setCursor(curCursor);
    }
    public void drawHighlightSquares(Graphics2D g2D, Rectangle2D r) {
      double x = r.getX();
      double y = r.getY();
      double w = r.getWidth();
      double h = r.getHeight();
      g2D.setColor(Color.black);
      g2D.fill(new Rectangle.Double(x - 3.0, y - 3.0, 6.0, 6.0));
      g2D
          .fill(new Rectangle.Double(x + w * 0.5 - 3.0, y - 3.0, 6.0,
              6.0));
      g2D.fill(new Rectangle.Double(x + w - 3.0, y - 3.0, 6.0, 6.0));
      g2D
          .fill(new Rectangle.Double(x - 3.0, y + h * 0.5 - 3.0, 6.0,
              6.0));
      g2D.fill(new Rectangle.Double(x + w - 3.0, y + h * 0.5 - 3.0, 6.0,
          6.0));
      g2D.fill(new Rectangle.Double(x - 3.0, y + h - 3.0, 6.0, 6.0));
      g2D.fill(new Rectangle.Double(x + w * 0.5 - 3.0, y + h - 3.0, 6.0,
          6.0));
      g2D.fill(new Rectangle.Double(x + w - 3.0, y + h - 3.0, 6.0, 6.0));
    }
    class MyMouseListener extends MouseAdapter {
      public void mousePressed(MouseEvent e) {
        if (ellipse.contains(e.getX(), e.getY())) {
          selectedShape = ellipse;
          if (boundingRec != null)
            boundingRec = ellipse.getBounds2D();
          displayParameters(selectedShape);
        } else { 
          boundingRec = null;
          location.setText("");
        }
        canvas.repaint();
        x1 = e.getX();
        y1 = e.getY();
      }
      public void mouseReleased(MouseEvent e) {
        if (ellipse.contains(e.getX(), e.getY())) {
          boundingRec = ellipse.getBounds2D();
          selectedShape = ellipse;
          displayParameters(selectedShape);
        }
        canvas.repaint();
      }
      public void mouseClicked(MouseEvent e) {
        if (ellipse.contains(e.getX(), e.getY())) {
          selectedShape = ellipse;
          boundingRec = ellipse.getBounds2D();
          displayParameters(selectedShape);
        } else {
          if (boundingRec != null)
            boundingRec = null;
          location.setText("");
        }
        canvas.repaint();
      }
    }
    class MyMouseMotionListener extends MouseMotionAdapter {
      public void mouseDragged(MouseEvent e) {
        if (ellipse.contains(e.getX(), e.getY())) {
          boundingRec = null;
          selectedShape = ellipse;
          x2 = e.getX();
          y2 = e.getY();
          x = x + x2 - x1;
          y = y + y2 - y1;
          x1 = x2;
          y1 = y2;
        }
        if (selectedShape != null)
          displayParameters(selectedShape);
        canvas.repaint();
      }
      public void mouseMoved(MouseEvent e) {
        if (ellipse != null) { 
          if (ellipse.contains(e.getX(), e.getY())) {
            curCursor = Cursor
                .getPredefinedCursor(Cursor.HAND_CURSOR);
          } else {
            curCursor = Cursor.getDefaultCursor();
          }
        }
        canvas.repaint();
      }
    }
    public void displayParameters(Shape shape) {
      double x = selectedShape.getX();
      double y = selectedShape.getY();
      double w = selectedShape.getWidth();
      double h = selectedShape.getHeight();
      String locString = "(" + Double.toString(x) + ","
          + Double.toString(y) + ")";
      String sizeString = "(" + Double.toString(w) + ","
          + Double.toString(h) + ")";
      location.setText(locString);
    }
  }
}



Polygon with float coordinates.

   
/*
   Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed with
   this work for additional information regarding copyright ownership.
   The ASF licenses this file to You under the Apache License, Version 2.0
   (the "License"); you may not use this file except in compliance with
   the License.  You may obtain a copy of the License at
       http://www.apache.org/licenses/LICENSE-2.0
   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
/**
 * This class is a Polygon with float coordinates.
 *
 * @version $Id: Polygon2D.java 594018 2007-11-12 04:17:41Z cam $
 */
public class Polygon2D implements Shape, Cloneable, Serializable {
    /**
     * The total number of points.  The value of <code>npoints</code>
     * represents the number of valid points in this <code>Polygon</code>.
     *
     */
    public int npoints;
    /**
     * The array of <i>x</i> coordinates. The value of {@link #npoints npoints} is equal to the
     * number of points in this <code>Polygon2D</code>.
     *
     */
    public float[] xpoints;
    /**
     * The array of <i>x</i> coordinates. The value of {@link #npoints npoints} is equal to the
     * number of points in this <code>Polygon2D</code>.
     *
     */
    public float[] ypoints;
    /**
     * Bounds of the Polygon2D.
     * @see #getBounds()
     */
    protected Rectangle2D bounds;
    private GeneralPath path;
    private GeneralPath closedPath;
    /**
     * Creates an empty Polygon2D.
     */
    public Polygon2D() {
        xpoints = new float[4];
        ypoints = new float[4];
    }
    /**
     * Constructs and initializes a <code>Polygon2D</code> from the specified
     * Rectangle2D.
     * @param rec the Rectangle2D
     * @exception  NullPointerException rec is <code>null</code>.
     */
    public Polygon2D(Rectangle2D rec) {
        if (rec == null) {
            throw new IndexOutOfBoundsException("null Rectangle");
        }
        npoints = 4;
        xpoints = new float[4];
        ypoints = new float[4];
        xpoints[0] = (float)rec.getMinX();
        ypoints[0] = (float)rec.getMinY();
        xpoints[1] = (float)rec.getMaxX();
        ypoints[1] = (float)rec.getMinY();
        xpoints[2] = (float)rec.getMaxX();
        ypoints[2] = (float)rec.getMaxY();
        xpoints[3] = (float)rec.getMinX();
        ypoints[3] = (float)rec.getMaxY();
        calculatePath();
    }
    /**
     * Constructs and initializes a <code>Polygon2D</code> from the specified
     * Polygon.
     * @param pol the Polygon
     * @exception  NullPointerException pol is <code>null</code>.
     */
    public Polygon2D(Polygon pol) {
        if (pol == null) {
            throw new IndexOutOfBoundsException("null Polygon");
        }
        this.npoints = pol.npoints;
        this.xpoints = new float[pol.npoints];
        this.ypoints = new float[pol.npoints];
        for (int i = 0; i < pol.npoints; i++) {
            xpoints[i] = pol.xpoints[i];
            ypoints[i] = pol.ypoints[i];
        }
        calculatePath();
    }
    /**
     * Constructs and initializes a <code>Polygon2D</code> from the specified
     * parameters.
     * @param xpoints an array of <i>x</i> coordinates
     * @param ypoints an array of <i>y</i> coordinates
     * @param npoints the total number of points in the <code>Polygon2D</code>
     * @exception  NegativeArraySizeException if the value of
     *                       <code>npoints</code> is negative.
     * @exception  IndexOutOfBoundsException if <code>npoints</code> is
     *             greater than the length of <code>xpoints</code>
     *             or the length of <code>ypoints</code>.
     * @exception  NullPointerException if <code>xpoints</code> or
     *             <code>ypoints</code> is <code>null</code>.
     */
    public Polygon2D(float[] xpoints, float[] ypoints, int npoints) {
        if (npoints > xpoints.length || npoints > ypoints.length) {
            throw new IndexOutOfBoundsException("npoints > xpoints.length || npoints > ypoints.length");
        }
        this.npoints = npoints;
        this.xpoints = new float[npoints];
        this.ypoints = new float[npoints];
        System.arraycopy(xpoints, 0, this.xpoints, 0, npoints);
        System.arraycopy(ypoints, 0, this.ypoints, 0, npoints);
        calculatePath();
    }
    /**
     * Constructs and initializes a <code>Polygon2D</code> from the specified
     * parameters.
     * @param xpoints an array of <i>x</i> coordinates
     * @param ypoints an array of <i>y</i> coordinates
     * @param npoints the total number of points in the <code>Polygon2D</code>
     * @exception  NegativeArraySizeException if the value of
     *                       <code>npoints</code> is negative.
     * @exception  IndexOutOfBoundsException if <code>npoints</code> is
     *             greater than the length of <code>xpoints</code>
     *             or the length of <code>ypoints</code>.
     * @exception  NullPointerException if <code>xpoints</code> or
     *             <code>ypoints</code> is <code>null</code>.
     */
    public Polygon2D(int[] xpoints, int[] ypoints, int npoints) {
        if (npoints > xpoints.length || npoints > ypoints.length) {
            throw new IndexOutOfBoundsException("npoints > xpoints.length || npoints > ypoints.length");
        }
        this.npoints = npoints;
        this.xpoints = new float[npoints];
        this.ypoints = new float[npoints];
        for (int i = 0; i < npoints; i++) {
            this.xpoints[i] = xpoints[i];
            this.ypoints[i] = ypoints[i];
        }
        calculatePath();
    }
    /**
     * Resets this <code>Polygon</code> object to an empty polygon.
     */
    public void reset() {
        npoints = 0;
        bounds = null;
        path = new GeneralPath();
        closedPath = null;
    }
    public Object clone() {
        Polygon2D pol = new Polygon2D();
        for (int i = 0; i < npoints; i++) {
            pol.addPoint(xpoints[i], ypoints[i]);
        }
        return pol;
    }
    private void calculatePath() {
        path = new GeneralPath();
        path.moveTo(xpoints[0], ypoints[0]);
        for (int i = 1; i < npoints; i++) {
            path.lineTo(xpoints[i], ypoints[i]);
        }
        bounds = path.getBounds2D();
        closedPath = null;
    }
    private void updatePath(float x, float y) {
        closedPath = null;
        if (path == null) {
            path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
            path.moveTo(x, y);
            bounds = new Rectangle2D.Float(x, y, 0, 0);
        } else {
            path.lineTo(x, y);
            float _xmax = (float)bounds.getMaxX();
            float _ymax = (float)bounds.getMaxY();
            float _xmin = (float)bounds.getMinX();
            float _ymin = (float)bounds.getMinY();
            if (x < _xmin) _xmin = x;
            else if (x > _xmax) _xmax = x;
            if (y < _ymin) _ymin = y;
            else if (y > _ymax) _ymax = y;
            bounds = new Rectangle2D.Float(_xmin, _ymin, _xmax - _xmin, _ymax - _ymin);
        }
    }
    /* get the associated {@link Polyline2D}.
     */
    public Polyline2D getPolyline2D() {
        Polyline2D pol = new Polyline2D( xpoints, ypoints, npoints );
        pol.addPoint( xpoints[0], ypoints[0]);
        return pol;
    }
    public Polygon getPolygon() {
        int[] _xpoints = new int[npoints];
        int[] _ypoints = new int[npoints];
        for (int i = 0; i < npoints; i++) {
            _xpoints[i] = (int)xpoints[i];     // todo maybe rounding is better ?
            _ypoints[i] = (int)ypoints[i];
        }
        return new Polygon(_xpoints, _ypoints, npoints);
    }
    public void addPoint(Point2D p) {
        addPoint((float)p.getX(), (float)p.getY());
    }
    /**
     * Appends the specified coordinates to this <code>Polygon2D</code>.
     * @param       x the specified x coordinate
     * @param       y the specified y coordinate
     */
    public void addPoint(float x, float y) {
        if (npoints == xpoints.length) {
            float[] tmp;
            tmp = new float[npoints * 2];
            System.arraycopy(xpoints, 0, tmp, 0, npoints);
            xpoints = tmp;
            tmp = new float[npoints * 2];
            System.arraycopy(ypoints, 0, tmp, 0, npoints);
            ypoints = tmp;
        }
        xpoints[npoints] = x;
        ypoints[npoints] = y;
        npoints++;
        updatePath(x, y);
    }
    /**
     * Determines whether the specified {@link Point} is inside this
     * <code>Polygon</code>.
     * @param p the specified <code>Point</code> to be tested
     * @return <code>true</code> if the <code>Polygon</code> contains the
     *                         <code>Point</code>; <code>false</code> otherwise.
     * @see #contains(double, double)
     */
    public boolean contains(Point p) {
        return contains(p.x, p.y);
    }
    /**
     * Determines whether the specified coordinates are inside this
     * <code>Polygon</code>.
     * <p>
     * @param x the specified x coordinate to be tested
     * @param y the specified y coordinate to be tested
     * @return  <code>true</code> if this <code>Polygon</code> contains
     *                         the specified coordinates, (<i>x</i>,&nbsp;<i>y</i>);
     *                         <code>false</code> otherwise.
     */
    public boolean contains(int x, int y) {
        return contains((double) x, (double) y);
    }
    /**
     * Returns the high precision bounding box of the {@link Shape}.
     * @return a {@link Rectangle2D} that precisely
     *                bounds the <code>Shape</code>.
     */
    public Rectangle2D getBounds2D() {
        return bounds;
    }
    public Rectangle getBounds() {
        if (bounds == null) return null;
        else return bounds.getBounds();
    }
    /**
     * Determines if the specified coordinates are inside this
     * <code>Polygon</code>.  For the definition of
     * <i>insideness</i>, see the class comments of {@link Shape}.
     * @param x the specified x coordinate
     * @param y the specified y coordinate
     * @return <code>true</code> if the <code>Polygon</code> contains the
     * specified coordinates; <code>false</code> otherwise.
     */
    public boolean contains(double x, double y) {
        if (npoints <= 2 || !bounds.contains(x, y)) {
            return false;
        }
        updateComputingPath();
        return closedPath.contains(x, y);
    }
    private void updateComputingPath() {
        if (npoints >= 1) {
            if (closedPath == null) {
                closedPath = (GeneralPath)path.clone();
                closedPath.closePath();
            }
        }
    }
    /**
     * Tests if a specified {@link Point2D} is inside the boundary of this
     * <code>Polygon</code>.
     * @param p a specified <code>Point2D</code>
     * @return <code>true</code> if this <code>Polygon</code> contains the
     *                 specified <code>Point2D</code>; <code>false</code>
     *          otherwise.
     * @see #contains(double, double)
     */
    public boolean contains(Point2D p) {
        return contains(p.getX(), p.getY());
    }
    /**
     * Tests if the interior of this <code>Polygon</code> intersects the
     * interior of a specified set of rectangular coordinates.
     * @param x the x coordinate of the specified rectangular
     *                        shape"s top-left corner
     * @param y the y coordinate of the specified rectangular
     *                        shape"s top-left corner
     * @param w the width of the specified rectangular shape
     * @param h the height of the specified rectangular shape
     * @return <code>true</code> if the interior of this
     *                        <code>Polygon</code> and the interior of the
     *                        specified set of rectangular
     *                         coordinates intersect each other;
     *                        <code>false</code> otherwise.
     */
    public boolean intersects(double x, double y, double w, double h) {
        if (npoints <= 0 || !bounds.intersects(x, y, w, h)) {
            return false;
        }
        updateComputingPath();
        return closedPath.intersects(x, y, w, h);
    }
    /**
     * Tests if the interior of this <code>Polygon</code> intersects the
     * interior of a specified <code>Rectangle2D</code>.
     * @param r a specified <code>Rectangle2D</code>
     * @return <code>true</code> if this <code>Polygon</code> and the
     *                         interior of the specified <code>Rectangle2D</code>
     *                         intersect each other; <code>false</code>
     *                         otherwise.
     */
    public boolean intersects(Rectangle2D r) {
        return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
    }
    /**
     * Tests if the interior of this <code>Polygon</code> entirely
     * contains the specified set of rectangular coordinates.
     * @param x the x coordinate of the top-left corner of the
     *                         specified set of rectangular coordinates
     * @param y the y coordinate of the top-left corner of the
     *                         specified set of rectangular coordinates
     * @param w the width of the set of rectangular coordinates
     * @param h the height of the set of rectangular coordinates
     * @return <code>true</code> if this <code>Polygon</code> entirely
     *                         contains the specified set of rectangular
     *                         coordinates; <code>false</code> otherwise.
     */
    public boolean contains(double x, double y, double w, double h) {
        if (npoints <= 0 || !bounds.intersects(x, y, w, h)) {
            return false;
        }
        updateComputingPath();
        return closedPath.contains(x, y, w, h);
    }
    /**
     * Tests if the interior of this <code>Polygon</code> entirely
     * contains the specified <code>Rectangle2D</code>.
     * @param r the specified <code>Rectangle2D</code>
     * @return <code>true</code> if this <code>Polygon</code> entirely
     *                         contains the specified <code>Rectangle2D</code>;
     *                        <code>false</code> otherwise.
     * @see #contains(double, double, double, double)
     */
    public boolean contains(Rectangle2D r) {
        return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
    }
    /**
     * Returns an iterator object that iterates along the boundary of this
     * <code>Polygon</code> and provides access to the geometry
     * of the outline of this <code>Polygon</code>.  An optional
     * {@link AffineTransform} can be specified so that the coordinates
     * returned in the iteration are transformed accordingly.
     * @param at an optional <code>AffineTransform</code> to be applied to the
     *                 coordinates as they are returned in the iteration, or
     *                <code>null</code> if untransformed coordinates are desired
     * @return a {@link PathIterator} object that provides access to the
     *                geometry of this <code>Polygon</code>.
     */
    public PathIterator getPathIterator(AffineTransform at) {
        updateComputingPath();
        if (closedPath == null) return null;
        else return closedPath.getPathIterator(at);
    }
    /**
     * Returns an iterator object that iterates along the boundary of
     * the <code>Polygon2D</code> and provides access to the geometry of the
     * outline of the <code>Shape</code>.  Only SEG_MOVETO, SEG_LINETO, and
     * SEG_CLOSE point types are returned by the iterator.
     * Since polygons are already flat, the <code>flatness</code> parameter
     * is ignored.
     * @param at an optional <code>AffineTransform</code> to be applied to the
     *                 coordinates as they are returned in the iteration, or
     *                <code>null</code> if untransformed coordinates are desired
     * @param flatness the maximum amount that the control points
     *                 for a given curve can vary from colinear before a subdivided
     *                curve is replaced by a straight line connecting the
     *                 endpoints.  Since polygons are already flat the
     *                 <code>flatness</code> parameter is ignored.
     * @return a <code>PathIterator</code> object that provides access to the
     *                 <code>Shape</code> object"s geometry.
     */
    public PathIterator getPathIterator(AffineTransform at, double flatness) {
        return getPathIterator(at);
    }
}
/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements.  See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License.  You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
* This class has the same behavior than {@link Polygon2D}, except that
* the figure is not closed.
*
* @version $Id: Polyline2D.java 594018 2007-11-12 04:17:41Z cam $
*/
class Polyline2D implements Shape, Cloneable, Serializable {
 private static final float ASSUME_ZERO = 0.001f;
 /**
  * The total number of points.  The value of <code>npoints</code>
  * represents the number of points in this <code>Polyline2D</code>.
  *
  */
 public int npoints;
 /**
  * The array of <i>x</i> coordinates. The value of {@link #npoints npoints} is equal to the
  * number of points in this <code>Polyline2D</code>.
  *
  */
 public float[] xpoints;
 /**
  * The array of <i>x</i> coordinates. The value of {@link #npoints npoints} is equal to the
  * number of points in this <code>Polyline2D</code>.
  *
  */
 public float[] ypoints;
 /**
  * Bounds of the Polyline2D.
  * @see #getBounds()
  */
 protected Rectangle2D bounds;
 private GeneralPath path;
 private GeneralPath closedPath;
 /**
  * Creates an empty Polyline2D.
  */
 public Polyline2D() {
     xpoints = new float[4];
     ypoints = new float[4];
 }
 /**
  * Constructs and initializes a <code>Polyline2D</code> from the specified
  * parameters.
  * @param xpoints an array of <i>x</i> coordinates
  * @param ypoints an array of <i>y</i> coordinates
  * @param npoints the total number of points in the
  *                                <code>Polyline2D</code>
  * @exception  NegativeArraySizeException if the value of
  *                       <code>npoints</code> is negative.
  * @exception  IndexOutOfBoundsException if <code>npoints</code> is
  *             greater than the length of <code>xpoints</code>
  *             or the length of <code>ypoints</code>.
  * @exception  NullPointerException if <code>xpoints</code> or
  *             <code>ypoints</code> is <code>null</code>.
  */
 public Polyline2D(float[] xpoints, float[] ypoints, int npoints) {
     if (npoints > xpoints.length || npoints > ypoints.length) {
         throw new IndexOutOfBoundsException("npoints > xpoints.length || npoints > ypoints.length");
     }
     this.npoints = npoints;
     this.xpoints = new float[npoints+1];   // make space for one more to close the polyline
     this.ypoints = new float[npoints+1];   // make space for one more to close the polyline
     System.arraycopy(xpoints, 0, this.xpoints, 0, npoints);
     System.arraycopy(ypoints, 0, this.ypoints, 0, npoints);
     calculatePath();
 }
 /**
  * Constructs and initializes a <code>Polyline2D</code> from the specified
  * parameters.
  * @param xpoints an array of <i>x</i> coordinates
  * @param ypoints an array of <i>y</i> coordinates
  * @param npoints the total number of points in the <code>Polyline2D</code>
  * @exception  NegativeArraySizeException if the value of
  *                       <code>npoints</code> is negative.
  * @exception  IndexOutOfBoundsException if <code>npoints</code> is
  *             greater than the length of <code>xpoints</code>
  *             or the length of <code>ypoints</code>.
  * @exception  NullPointerException if <code>xpoints</code> or
  *             <code>ypoints</code> is <code>null</code>.
  */
 public Polyline2D(int[] xpoints, int[] ypoints, int npoints) {
     if (npoints > xpoints.length || npoints > ypoints.length) {
         throw new IndexOutOfBoundsException("npoints > xpoints.length || npoints > ypoints.length");
     }
     this.npoints = npoints;
     this.xpoints = new float[npoints];
     this.ypoints = new float[npoints];
     for (int i = 0; i < npoints; i++) {
         this.xpoints[i] = xpoints[i];
         this.ypoints[i] = ypoints[i];
     }
     calculatePath();
 }
 public Polyline2D(Line2D line) {
     npoints = 2;
     xpoints = new float[2];
     ypoints = new float[2];
     xpoints[0] = (float)line.getX1();
     xpoints[1] = (float)line.getX2();
     ypoints[0] = (float)line.getY1();
     ypoints[1] = (float)line.getY2();
     calculatePath();
 }
 /**
  * Resets this <code>Polyline2D</code> object to an empty polygon.
  * The coordinate arrays and the data in them are left untouched
  * but the number of points is reset to zero to mark the old
  * vertex data as invalid and to start accumulating new vertex
  * data at the beginning.
  * All internally-cached data relating to the old vertices
  * are discarded.
  * Note that since the coordinate arrays from before the reset
  * are reused, creating a new empty <code>Polyline2D</code> might
  * be more memory efficient than resetting the current one if
  * the number of vertices in the new polyline data is significantly
  * smaller than the number of vertices in the data from before the
  * reset.
  */
 public void reset() {
     npoints = 0;
     bounds = null;
     path = new GeneralPath();
     closedPath = null;
 }
 public Object clone() {
     Polyline2D pol = new Polyline2D();
     for (int i = 0; i < npoints; i++) {
         pol.addPoint(xpoints[i], ypoints[i]);
     }
     return pol;
 }
 private void calculatePath() {
     path = new GeneralPath();
     path.moveTo(xpoints[0], ypoints[0]);
     for (int i = 1; i < npoints; i++) {
         path.lineTo(xpoints[i], ypoints[i]);
     }
     bounds = path.getBounds2D();
     closedPath = null;
 }
 private void updatePath(float x, float y) {
     closedPath = null;
     if (path == null) {
         path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
         path.moveTo(x, y);
         bounds = new Rectangle2D.Float(x, y, 0, 0);
     } else {
         path.lineTo(x, y);
         float _xmax = (float)bounds.getMaxX();
         float _ymax = (float)bounds.getMaxY();
         float _xmin = (float)bounds.getMinX();
         float _ymin = (float)bounds.getMinY();
         if (x < _xmin) _xmin = x;
         else if (x > _xmax) _xmax = x;
         if (y < _ymin) _ymin = y;
         else if (y > _ymax) _ymax = y;
         bounds = new Rectangle2D.Float(_xmin, _ymin, _xmax - _xmin, _ymax - _ymin);
     }
 }
 public void addPoint(Point2D p) {
     addPoint((float)p.getX(), (float)p.getY());
 }
 /**
  * Appends the specified coordinates to this <code>Polyline2D</code>.
  * <p>
  * If an operation that calculates the bounding box of this
  * <code>Polyline2D</code> has already been performed, such as
  * <code>getBounds</code> or <code>contains</code>, then this
  * method updates the bounding box.
  * @param       x the specified x coordinate
  * @param       y the specified y coordinate
  * @see         java.awt.Polygon#getBounds
  * @see         java.awt.Polygon#contains(double,double)
  */
 public void addPoint(float x, float y) {
     if (npoints == xpoints.length) {
         float[] tmp;
         tmp = new float[npoints * 2];
         System.arraycopy(xpoints, 0, tmp, 0, npoints);
         xpoints = tmp;
         tmp = new float[npoints * 2];
         System.arraycopy(ypoints, 0, tmp, 0, npoints);
         ypoints = tmp;
     }
     xpoints[npoints] = x;
     ypoints[npoints] = y;
     npoints++;
     updatePath(x, y);
 }
 /**
  * Gets the bounding box of this <code>Polyline2D</code>.
  * The bounding box is the smallest {@link Rectangle} whose
  * sides are parallel to the x and y axes of the
  * coordinate space, and can completely contain the <code>Polyline2D</code>.
  * @return a <code>Rectangle</code> that defines the bounds of this
  * <code>Polyline2D</code>.
  */
 public Rectangle getBounds() {
     if (bounds == null) return null;
     else return bounds.getBounds();
 }
 private void updateComputingPath() {
     if (npoints >= 1) {
         if (closedPath == null) {
             closedPath = (GeneralPath)path.clone();
             closedPath.closePath();
         }
     }
 }
 /**
  * Determines whether the specified {@link Point} is inside this
  * <code>Polyline2D</code>.
  * This method is required to implement the Shape interface,
  * but in the case of Line2D objects it always returns false since a line contains no area.
  */
 public boolean contains(Point p) {
     return false;
 }
 /**
  * Determines if the specified coordinates are inside this
  * <code>Polyline2D</code>.
  * This method is required to implement the Shape interface,
  * but in the case of Line2D objects it always returns false since a line contains no area.
  */
 public boolean contains(double x, double y) {
     return false;
 }
 /**
  * Determines whether the specified coordinates are inside this
  * <code>Polyline2D</code>.
  * This method is required to implement the Shape interface,
  * but in the case of Line2D objects it always returns false since a line contains no area.
  */
 public boolean contains(int x, int y) {
     return false;
 }
 /**
  * Returns the high precision bounding box of the {@link Shape}.
  * @return a {@link Rectangle2D} that precisely
  *                bounds the <code>Shape</code>.
  */
 public Rectangle2D getBounds2D() {
     return bounds;
 }
 /**
  * Tests if a specified {@link Point2D} is inside the boundary of this
  * <code>Polyline2D</code>.
  * This method is required to implement the Shape interface,
  * but in the case of Line2D objects it always returns false since a line contains no area.
  */
 public boolean contains(Point2D p) {
     return false;
 }
 /**
  * Tests if the interior of this <code>Polygon</code> intersects the
  * interior of a specified set of rectangular coordinates.
  * @param x the x coordinate of the specified rectangular
  *                        shape"s top-left corner
  * @param y the y coordinate of the specified rectangular
  *                        shape"s top-left corner
  * @param w the width of the specified rectangular shape
  * @param h the height of the specified rectangular shape
  * @return <code>true</code> if the interior of this
  *                        <code>Polygon</code> and the interior of the
  *                        specified set of rectangular
  *                         coordinates intersect each other;
  *                        <code>false</code> otherwise.
  */
 public boolean intersects(double x, double y, double w, double h) {
     if (npoints <= 0 || !bounds.intersects(x, y, w, h)) {
         return false;
     }
     updateComputingPath();
     return closedPath.intersects(x, y, w, h);
 }
 /**
  * Tests if the interior of this <code>Polygon</code> intersects the
  * interior of a specified <code>Rectangle2D</code>.
  * @param r a specified <code>Rectangle2D</code>
  * @return <code>true</code> if this <code>Polygon</code> and the
  *                         interior of the specified <code>Rectangle2D</code>
  *                         intersect each other; <code>false</code>
  *                         otherwise.
  */
 public boolean intersects(Rectangle2D r) {
     return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
 }
 /**
  * Tests if the interior of this <code>Polyline2D</code> entirely
  * contains the specified set of rectangular coordinates.
  * This method is required to implement the Shape interface,
  * but in the case of Line2D objects it always returns false since a line contains no area.
  */
 public boolean contains(double x, double y, double w, double h) {
     return false;
 }
 /**
  * Tests if the interior of this <code>Polyline2D</code> entirely
  * contains the specified <code>Rectangle2D</code>.
  * This method is required to implement the Shape interface,
  * but in the case of Line2D objects it always returns false since a line contains no area.
  */
 public boolean contains(Rectangle2D r) {
     return false;
 }
 /**
  * Returns an iterator object that iterates along the boundary of this
  * <code>Polygon</code> and provides access to the geometry
  * of the outline of this <code>Polygon</code>.  An optional
  * {@link AffineTransform} can be specified so that the coordinates
  * returned in the iteration are transformed accordingly.
  * @param at an optional <code>AffineTransform</code> to be applied to the
  *                 coordinates as they are returned in the iteration, or
  *                <code>null</code> if untransformed coordinates are desired
  * @return a {@link PathIterator} object that provides access to the
  *                geometry of this <code>Polygon</code>.
  */
 public PathIterator getPathIterator(AffineTransform at) {
     if (path == null) return null;
     else return path.getPathIterator(at);
 }
 /* get the associated {@link Polygon2D}.
  * This method take care that may be the last point can
  * be equal to the first. In that case it must not be included in the Polygon,
  * as polygons declare their first point only once.
  */
 public Polygon2D getPolygon2D() {
     Polygon2D pol = new Polygon2D();
     for (int i = 0; i < npoints - 1; i++) {
        pol.addPoint(xpoints[i], ypoints[i]);
     }
     Point2D.Double p0 =
         new Point2D.Double(xpoints[0], ypoints[0]);
     Point2D.Double p1 =
         new Point2D.Double(xpoints[npoints-1], ypoints[npoints-1]);
     if (p0.distance(p1) > ASSUME_ZERO)
         pol.addPoint(xpoints[npoints-1], ypoints[npoints-1]);
     return pol;
 }
 /**
  * Returns an iterator object that iterates along the boundary of
  * the <code>Shape</code> and provides access to the geometry of the
  * outline of the <code>Shape</code>.  Only SEG_MOVETO and SEG_LINETO, point types
  * are returned by the iterator.
  * Since polylines are already flat, the <code>flatness</code> parameter
  * is ignored.
  * @param at an optional <code>AffineTransform</code> to be applied to the
  *                 coordinates as they are returned in the iteration, or
  *                <code>null</code> if untransformed coordinates are desired
  * @param flatness the maximum amount that the control points
  *                 for a given curve can vary from colinear before a subdivided
  *                curve is replaced by a straight line connecting the
  *                 endpoints.  Since polygons are already flat the
  *                 <code>flatness</code> parameter is ignored.
  * @return a <code>PathIterator</code> object that provides access to the
  *                 <code>Shape</code> object"s geometry.
  */
 public PathIterator getPathIterator(AffineTransform at, double flatness) {
     return path.getPathIterator(at);
 }
}



Polyline 2D

   
/*
   Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed with
   this work for additional information regarding copyright ownership.
   The ASF licenses this file to You under the Apache License, Version 2.0
   (the "License"); you may not use this file except in compliance with
   the License.  You may obtain a copy of the License at
       http://www.apache.org/licenses/LICENSE-2.0
   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.Serializable;
/**
 * This class has the same behavior than {@link Polygon2D}, except that
 * the figure is not closed.
 *
 * @version $Id: Polyline2D.java 594018 2007-11-12 04:17:41Z cam $
 */
public class Polyline2D implements Shape, Cloneable, Serializable {
    private static final float ASSUME_ZERO = 0.001f;
    /**
     * The total number of points.  The value of <code>npoints</code>
     * represents the number of points in this <code>Polyline2D</code>.
     *
     */
    public int npoints;
    /**
     * The array of <i>x</i> coordinates. The value of {@link #npoints npoints} is equal to the
     * number of points in this <code>Polyline2D</code>.
     *
     */
    public float[] xpoints;
    /**
     * The array of <i>x</i> coordinates. The value of {@link #npoints npoints} is equal to the
     * number of points in this <code>Polyline2D</code>.
     *
     */
    public float[] ypoints;
    /**
     * Bounds of the Polyline2D.
     * @see #getBounds()
     */
    protected Rectangle2D bounds;
    private GeneralPath path;
    private GeneralPath closedPath;
    /**
     * Creates an empty Polyline2D.
     */
    public Polyline2D() {
        xpoints = new float[4];
        ypoints = new float[4];
    }
    /**
     * Constructs and initializes a <code>Polyline2D</code> from the specified
     * parameters.
     * @param xpoints an array of <i>x</i> coordinates
     * @param ypoints an array of <i>y</i> coordinates
     * @param npoints the total number of points in the
     *                                <code>Polyline2D</code>
     * @exception  NegativeArraySizeException if the value of
     *                       <code>npoints</code> is negative.
     * @exception  IndexOutOfBoundsException if <code>npoints</code> is
     *             greater than the length of <code>xpoints</code>
     *             or the length of <code>ypoints</code>.
     * @exception  NullPointerException if <code>xpoints</code> or
     *             <code>ypoints</code> is <code>null</code>.
     */
    public Polyline2D(float[] xpoints, float[] ypoints, int npoints) {
        if (npoints > xpoints.length || npoints > ypoints.length) {
            throw new IndexOutOfBoundsException("npoints > xpoints.length || npoints > ypoints.length");
        }
        this.npoints = npoints;
        this.xpoints = new float[npoints+1];   // make space for one more to close the polyline
        this.ypoints = new float[npoints+1];   // make space for one more to close the polyline
        System.arraycopy(xpoints, 0, this.xpoints, 0, npoints);
        System.arraycopy(ypoints, 0, this.ypoints, 0, npoints);
        calculatePath();
    }
    /**
     * Constructs and initializes a <code>Polyline2D</code> from the specified
     * parameters.
     * @param xpoints an array of <i>x</i> coordinates
     * @param ypoints an array of <i>y</i> coordinates
     * @param npoints the total number of points in the <code>Polyline2D</code>
     * @exception  NegativeArraySizeException if the value of
     *                       <code>npoints</code> is negative.
     * @exception  IndexOutOfBoundsException if <code>npoints</code> is
     *             greater than the length of <code>xpoints</code>
     *             or the length of <code>ypoints</code>.
     * @exception  NullPointerException if <code>xpoints</code> or
     *             <code>ypoints</code> is <code>null</code>.
     */
    public Polyline2D(int[] xpoints, int[] ypoints, int npoints) {
        if (npoints > xpoints.length || npoints > ypoints.length) {
            throw new IndexOutOfBoundsException("npoints > xpoints.length || npoints > ypoints.length");
        }
        this.npoints = npoints;
        this.xpoints = new float[npoints];
        this.ypoints = new float[npoints];
        for (int i = 0; i < npoints; i++) {
            this.xpoints[i] = xpoints[i];
            this.ypoints[i] = ypoints[i];
        }
        calculatePath();
    }
    public Polyline2D(Line2D line) {
        npoints = 2;
        xpoints = new float[2];
        ypoints = new float[2];
        xpoints[0] = (float)line.getX1();
        xpoints[1] = (float)line.getX2();
        ypoints[0] = (float)line.getY1();
        ypoints[1] = (float)line.getY2();
        calculatePath();
    }
    /**
     * Resets this <code>Polyline2D</code> object to an empty polygon.
     * The coordinate arrays and the data in them are left untouched
     * but the number of points is reset to zero to mark the old
     * vertex data as invalid and to start accumulating new vertex
     * data at the beginning.
     * All internally-cached data relating to the old vertices
     * are discarded.
     * Note that since the coordinate arrays from before the reset
     * are reused, creating a new empty <code>Polyline2D</code> might
     * be more memory efficient than resetting the current one if
     * the number of vertices in the new polyline data is significantly
     * smaller than the number of vertices in the data from before the
     * reset.
     */
    public void reset() {
        npoints = 0;
        bounds = null;
        path = new GeneralPath();
        closedPath = null;
    }
    public Object clone() {
        Polyline2D pol = new Polyline2D();
        for (int i = 0; i < npoints; i++) {
            pol.addPoint(xpoints[i], ypoints[i]);
        }
        return pol;
    }
    private void calculatePath() {
        path = new GeneralPath();
        path.moveTo(xpoints[0], ypoints[0]);
        for (int i = 1; i < npoints; i++) {
            path.lineTo(xpoints[i], ypoints[i]);
        }
        bounds = path.getBounds2D();
        closedPath = null;
    }
    private void updatePath(float x, float y) {
        closedPath = null;
        if (path == null) {
            path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
            path.moveTo(x, y);
            bounds = new Rectangle2D.Float(x, y, 0, 0);
        } else {
            path.lineTo(x, y);
            float _xmax = (float)bounds.getMaxX();
            float _ymax = (float)bounds.getMaxY();
            float _xmin = (float)bounds.getMinX();
            float _ymin = (float)bounds.getMinY();
            if (x < _xmin) _xmin = x;
            else if (x > _xmax) _xmax = x;
            if (y < _ymin) _ymin = y;
            else if (y > _ymax) _ymax = y;
            bounds = new Rectangle2D.Float(_xmin, _ymin, _xmax - _xmin, _ymax - _ymin);
        }
    }
    public void addPoint(Point2D p) {
        addPoint((float)p.getX(), (float)p.getY());
    }
    /**
     * Appends the specified coordinates to this <code>Polyline2D</code>.
     * <p>
     * If an operation that calculates the bounding box of this
     * <code>Polyline2D</code> has already been performed, such as
     * <code>getBounds</code> or <code>contains</code>, then this
     * method updates the bounding box.
     * @param       x the specified x coordinate
     * @param       y the specified y coordinate
     * @see         java.awt.Polygon#getBounds
     * @see         java.awt.Polygon#contains(double,double)
     */
    public void addPoint(float x, float y) {
        if (npoints == xpoints.length) {
            float[] tmp;
            tmp = new float[npoints * 2];
            System.arraycopy(xpoints, 0, tmp, 0, npoints);
            xpoints = tmp;
            tmp = new float[npoints * 2];
            System.arraycopy(ypoints, 0, tmp, 0, npoints);
            ypoints = tmp;
        }
        xpoints[npoints] = x;
        ypoints[npoints] = y;
        npoints++;
        updatePath(x, y);
    }
    /**
     * Gets the bounding box of this <code>Polyline2D</code>.
     * The bounding box is the smallest {@link Rectangle} whose
     * sides are parallel to the x and y axes of the
     * coordinate space, and can completely contain the <code>Polyline2D</code>.
     * @return a <code>Rectangle</code> that defines the bounds of this
     * <code>Polyline2D</code>.
     */
    public Rectangle getBounds() {
        if (bounds == null) return null;
        else return bounds.getBounds();
    }
    private void updateComputingPath() {
        if (npoints >= 1) {
            if (closedPath == null) {
                closedPath = (GeneralPath)path.clone();
                closedPath.closePath();
            }
        }
    }
    /**
     * Determines whether the specified {@link Point} is inside this
     * <code>Polyline2D</code>.
     * This method is required to implement the Shape interface,
     * but in the case of Line2D objects it always returns false since a line contains no area.
     */
    public boolean contains(Point p) {
        return false;
    }
    /**
     * Determines if the specified coordinates are inside this
     * <code>Polyline2D</code>.
     * This method is required to implement the Shape interface,
     * but in the case of Line2D objects it always returns false since a line contains no area.
     */
    public boolean contains(double x, double y) {
        return false;
    }
    /**
     * Determines whether the specified coordinates are inside this
     * <code>Polyline2D</code>.
     * This method is required to implement the Shape interface,
     * but in the case of Line2D objects it always returns false since a line contains no area.
     */
    public boolean contains(int x, int y) {
        return false;
    }
    /**
     * Returns the high precision bounding box of the {@link Shape}.
     * @return a {@link Rectangle2D} that precisely
     *                bounds the <code>Shape</code>.
     */
    public Rectangle2D getBounds2D() {
        return bounds;
    }
    /**
     * Tests if a specified {@link Point2D} is inside the boundary of this
     * <code>Polyline2D</code>.
     * This method is required to implement the Shape interface,
     * but in the case of Line2D objects it always returns false since a line contains no area.
     */
    public boolean contains(Point2D p) {
        return false;
    }
    /**
     * Tests if the interior of this <code>Polygon</code> intersects the
     * interior of a specified set of rectangular coordinates.
     * @param x the x coordinate of the specified rectangular
     *                        shape"s top-left corner
     * @param y the y coordinate of the specified rectangular
     *                        shape"s top-left corner
     * @param w the width of the specified rectangular shape
     * @param h the height of the specified rectangular shape
     * @return <code>true</code> if the interior of this
     *                        <code>Polygon</code> and the interior of the
     *                        specified set of rectangular
     *                         coordinates intersect each other;
     *                        <code>false</code> otherwise.
     */
    public boolean intersects(double x, double y, double w, double h) {
        if (npoints <= 0 || !bounds.intersects(x, y, w, h)) {
            return false;
        }
        updateComputingPath();
        return closedPath.intersects(x, y, w, h);
    }
    /**
     * Tests if the interior of this <code>Polygon</code> intersects the
     * interior of a specified <code>Rectangle2D</code>.
     * @param r a specified <code>Rectangle2D</code>
     * @return <code>true</code> if this <code>Polygon</code> and the
     *                         interior of the specified <code>Rectangle2D</code>
     *                         intersect each other; <code>false</code>
     *                         otherwise.
     */
    public boolean intersects(Rectangle2D r) {
        return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
    }
    /**
     * Tests if the interior of this <code>Polyline2D</code> entirely
     * contains the specified set of rectangular coordinates.
     * This method is required to implement the Shape interface,
     * but in the case of Line2D objects it always returns false since a line contains no area.
     */
    public boolean contains(double x, double y, double w, double h) {
        return false;
    }
    /**
     * Tests if the interior of this <code>Polyline2D</code> entirely
     * contains the specified <code>Rectangle2D</code>.
     * This method is required to implement the Shape interface,
     * but in the case of Line2D objects it always returns false since a line contains no area.
     */
    public boolean contains(Rectangle2D r) {
        return false;
    }
    /**
     * Returns an iterator object that iterates along the boundary of this
     * <code>Polygon</code> and provides access to the geometry
     * of the outline of this <code>Polygon</code>.  An optional
     * {@link AffineTransform} can be specified so that the coordinates
     * returned in the iteration are transformed accordingly.
     * @param at an optional <code>AffineTransform</code> to be applied to the
     *                 coordinates as they are returned in the iteration, or
     *                <code>null</code> if untransformed coordinates are desired
     * @return a {@link PathIterator} object that provides access to the
     *                geometry of this <code>Polygon</code>.
     */
    public PathIterator getPathIterator(AffineTransform at) {
        if (path == null) return null;
        else return path.getPathIterator(at);
    }
    /* get the associated {@link Polygon2D}.
     * This method take care that may be the last point can
     * be equal to the first. In that case it must not be included in the Polygon,
     * as polygons declare their first point only once.
     */
    public Polygon2D getPolygon2D() {
        Polygon2D pol = new Polygon2D();
        for (int i = 0; i < npoints - 1; i++) {
           pol.addPoint(xpoints[i], ypoints[i]);
        }
        Point2D.Double p0 =
            new Point2D.Double(xpoints[0], ypoints[0]);
        Point2D.Double p1 =
            new Point2D.Double(xpoints[npoints-1], ypoints[npoints-1]);
        if (p0.distance(p1) > ASSUME_ZERO)
            pol.addPoint(xpoints[npoints-1], ypoints[npoints-1]);
        return pol;
    }
    /**
     * Returns an iterator object that iterates along the boundary of
     * the <code>Shape</code> and provides access to the geometry of the
     * outline of the <code>Shape</code>.  Only SEG_MOVETO and SEG_LINETO, point types
     * are returned by the iterator.
     * Since polylines are already flat, the <code>flatness</code> parameter
     * is ignored.
     * @param at an optional <code>AffineTransform</code> to be applied to the
     *                 coordinates as they are returned in the iteration, or
     *                <code>null</code> if untransformed coordinates are desired
     * @param flatness the maximum amount that the control points
     *                 for a given curve can vary from colinear before a subdivided
     *                curve is replaced by a straight line connecting the
     *                 endpoints.  Since polygons are already flat the
     *                 <code>flatness</code> parameter is ignored.
     * @return a <code>PathIterator</code> object that provides access to the
     *                 <code>Shape</code> object"s geometry.
     */
    public PathIterator getPathIterator(AffineTransform at, double flatness) {
        return path.getPathIterator(at);
    }
}
/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements.  See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License.  You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
* This class is a Polygon with float coordinates.
*
* @version $Id: Polygon2D.java 594018 2007-11-12 04:17:41Z cam $
*/
class Polygon2D implements Shape, Cloneable, Serializable {
 /**
  * The total number of points.  The value of <code>npoints</code>
  * represents the number of valid points in this <code>Polygon</code>.
  *
  */
 public int npoints;
 /**
  * The array of <i>x</i> coordinates. The value of {@link #npoints npoints} is equal to the
  * number of points in this <code>Polygon2D</code>.
  *
  */
 public float[] xpoints;
 /**
  * The array of <i>x</i> coordinates. The value of {@link #npoints npoints} is equal to the
  * number of points in this <code>Polygon2D</code>.
  *
  */
 public float[] ypoints;
 /**
  * Bounds of the Polygon2D.
  * @see #getBounds()
  */
 protected Rectangle2D bounds;
 private GeneralPath path;
 private GeneralPath closedPath;
 /**
  * Creates an empty Polygon2D.
  */
 public Polygon2D() {
     xpoints = new float[4];
     ypoints = new float[4];
 }
 /**
  * Constructs and initializes a <code>Polygon2D</code> from the specified
  * Rectangle2D.
  * @param rec the Rectangle2D
  * @exception  NullPointerException rec is <code>null</code>.
  */
 public Polygon2D(Rectangle2D rec) {
     if (rec == null) {
         throw new IndexOutOfBoundsException("null Rectangle");
     }
     npoints = 4;
     xpoints = new float[4];
     ypoints = new float[4];
     xpoints[0] = (float)rec.getMinX();
     ypoints[0] = (float)rec.getMinY();
     xpoints[1] = (float)rec.getMaxX();
     ypoints[1] = (float)rec.getMinY();
     xpoints[2] = (float)rec.getMaxX();
     ypoints[2] = (float)rec.getMaxY();
     xpoints[3] = (float)rec.getMinX();
     ypoints[3] = (float)rec.getMaxY();
     calculatePath();
 }
 /**
  * Constructs and initializes a <code>Polygon2D</code> from the specified
  * Polygon.
  * @param pol the Polygon
  * @exception  NullPointerException pol is <code>null</code>.
  */
 public Polygon2D(Polygon pol) {
     if (pol == null) {
         throw new IndexOutOfBoundsException("null Polygon");
     }
     this.npoints = pol.npoints;
     this.xpoints = new float[pol.npoints];
     this.ypoints = new float[pol.npoints];
     for (int i = 0; i < pol.npoints; i++) {
         xpoints[i] = pol.xpoints[i];
         ypoints[i] = pol.ypoints[i];
     }
     calculatePath();
 }
 /**
  * Constructs and initializes a <code>Polygon2D</code> from the specified
  * parameters.
  * @param xpoints an array of <i>x</i> coordinates
  * @param ypoints an array of <i>y</i> coordinates
  * @param npoints the total number of points in the <code>Polygon2D</code>
  * @exception  NegativeArraySizeException if the value of
  *                       <code>npoints</code> is negative.
  * @exception  IndexOutOfBoundsException if <code>npoints</code> is
  *             greater than the length of <code>xpoints</code>
  *             or the length of <code>ypoints</code>.
  * @exception  NullPointerException if <code>xpoints</code> or
  *             <code>ypoints</code> is <code>null</code>.
  */
 public Polygon2D(float[] xpoints, float[] ypoints, int npoints) {
     if (npoints > xpoints.length || npoints > ypoints.length) {
         throw new IndexOutOfBoundsException("npoints > xpoints.length || npoints > ypoints.length");
     }
     this.npoints = npoints;
     this.xpoints = new float[npoints];
     this.ypoints = new float[npoints];
     System.arraycopy(xpoints, 0, this.xpoints, 0, npoints);
     System.arraycopy(ypoints, 0, this.ypoints, 0, npoints);
     calculatePath();
 }
 /**
  * Constructs and initializes a <code>Polygon2D</code> from the specified
  * parameters.
  * @param xpoints an array of <i>x</i> coordinates
  * @param ypoints an array of <i>y</i> coordinates
  * @param npoints the total number of points in the <code>Polygon2D</code>
  * @exception  NegativeArraySizeException if the value of
  *                       <code>npoints</code> is negative.
  * @exception  IndexOutOfBoundsException if <code>npoints</code> is
  *             greater than the length of <code>xpoints</code>
  *             or the length of <code>ypoints</code>.
  * @exception  NullPointerException if <code>xpoints</code> or
  *             <code>ypoints</code> is <code>null</code>.
  */
 public Polygon2D(int[] xpoints, int[] ypoints, int npoints) {
     if (npoints > xpoints.length || npoints > ypoints.length) {
         throw new IndexOutOfBoundsException("npoints > xpoints.length || npoints > ypoints.length");
     }
     this.npoints = npoints;
     this.xpoints = new float[npoints];
     this.ypoints = new float[npoints];
     for (int i = 0; i < npoints; i++) {
         this.xpoints[i] = xpoints[i];
         this.ypoints[i] = ypoints[i];
     }
     calculatePath();
 }
 /**
  * Resets this <code>Polygon</code> object to an empty polygon.
  */
 public void reset() {
     npoints = 0;
     bounds = null;
     path = new GeneralPath();
     closedPath = null;
 }
 public Object clone() {
     Polygon2D pol = new Polygon2D();
     for (int i = 0; i < npoints; i++) {
         pol.addPoint(xpoints[i], ypoints[i]);
     }
     return pol;
 }
 private void calculatePath() {
     path = new GeneralPath();
     path.moveTo(xpoints[0], ypoints[0]);
     for (int i = 1; i < npoints; i++) {
         path.lineTo(xpoints[i], ypoints[i]);
     }
     bounds = path.getBounds2D();
     closedPath = null;
 }
 private void updatePath(float x, float y) {
     closedPath = null;
     if (path == null) {
         path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
         path.moveTo(x, y);
         bounds = new Rectangle2D.Float(x, y, 0, 0);
     } else {
         path.lineTo(x, y);
         float _xmax = (float)bounds.getMaxX();
         float _ymax = (float)bounds.getMaxY();
         float _xmin = (float)bounds.getMinX();
         float _ymin = (float)bounds.getMinY();
         if (x < _xmin) _xmin = x;
         else if (x > _xmax) _xmax = x;
         if (y < _ymin) _ymin = y;
         else if (y > _ymax) _ymax = y;
         bounds = new Rectangle2D.Float(_xmin, _ymin, _xmax - _xmin, _ymax - _ymin);
     }
 }
 /* get the associated {@link Polyline2D}.
  */
 public Polyline2D getPolyline2D() {
     Polyline2D pol = new Polyline2D( xpoints, ypoints, npoints );
     pol.addPoint( xpoints[0], ypoints[0]);
     return pol;
 }
 public Polygon getPolygon() {
     int[] _xpoints = new int[npoints];
     int[] _ypoints = new int[npoints];
     for (int i = 0; i < npoints; i++) {
         _xpoints[i] = (int)xpoints[i];     // todo maybe rounding is better ?
         _ypoints[i] = (int)ypoints[i];
     }
     return new Polygon(_xpoints, _ypoints, npoints);
 }
 public void addPoint(Point2D p) {
     addPoint((float)p.getX(), (float)p.getY());
 }
 /**
  * Appends the specified coordinates to this <code>Polygon2D</code>.
  * @param       x the specified x coordinate
  * @param       y the specified y coordinate
  */
 public void addPoint(float x, float y) {
     if (npoints == xpoints.length) {
         float[] tmp;
         tmp = new float[npoints * 2];
         System.arraycopy(xpoints, 0, tmp, 0, npoints);
         xpoints = tmp;
         tmp = new float[npoints * 2];
         System.arraycopy(ypoints, 0, tmp, 0, npoints);
         ypoints = tmp;
     }
     xpoints[npoints] = x;
     ypoints[npoints] = y;
     npoints++;
     updatePath(x, y);
 }
 /**
  * Determines whether the specified {@link Point} is inside this
  * <code>Polygon</code>.
  * @param p the specified <code>Point</code> to be tested
  * @return <code>true</code> if the <code>Polygon</code> contains the
  *                         <code>Point</code>; <code>false</code> otherwise.
  * @see #contains(double, double)
  */
 public boolean contains(Point p) {
     return contains(p.x, p.y);
 }
 /**
  * Determines whether the specified coordinates are inside this
  * <code>Polygon</code>.
  * <p>
  * @param x the specified x coordinate to be tested
  * @param y the specified y coordinate to be tested
  * @return  <code>true</code> if this <code>Polygon</code> contains
  *                         the specified coordinates, (<i>x</i>,&nbsp;<i>y</i>);
  *                         <code>false</code> otherwise.
  */
 public boolean contains(int x, int y) {
     return contains((double) x, (double) y);
 }
 /**
  * Returns the high precision bounding box of the {@link Shape}.
  * @return a {@link Rectangle2D} that precisely
  *                bounds the <code>Shape</code>.
  */
 public Rectangle2D getBounds2D() {
     return bounds;
 }
 public Rectangle getBounds() {
     if (bounds == null) return null;
     else return bounds.getBounds();
 }
 /**
  * Determines if the specified coordinates are inside this
  * <code>Polygon</code>.  For the definition of
  * <i>insideness</i>, see the class comments of {@link Shape}.
  * @param x the specified x coordinate
  * @param y the specified y coordinate
  * @return <code>true</code> if the <code>Polygon</code> contains the
  * specified coordinates; <code>false</code> otherwise.
  */
 public boolean contains(double x, double y) {
     if (npoints <= 2 || !bounds.contains(x, y)) {
         return false;
     }
     updateComputingPath();
     return closedPath.contains(x, y);
 }
 private void updateComputingPath() {
     if (npoints >= 1) {
         if (closedPath == null) {
             closedPath = (GeneralPath)path.clone();
             closedPath.closePath();
         }
     }
 }
 /**
  * Tests if a specified {@link Point2D} is inside the boundary of this
  * <code>Polygon</code>.
  * @param p a specified <code>Point2D</code>
  * @return <code>true</code> if this <code>Polygon</code> contains the
  *                 specified <code>Point2D</code>; <code>false</code>
  *          otherwise.
  * @see #contains(double, double)
  */
 public boolean contains(Point2D p) {
     return contains(p.getX(), p.getY());
 }
 /**
  * Tests if the interior of this <code>Polygon</code> intersects the
  * interior of a specified set of rectangular coordinates.
  * @param x the x coordinate of the specified rectangular
  *                        shape"s top-left corner
  * @param y the y coordinate of the specified rectangular
  *                        shape"s top-left corner
  * @param w the width of the specified rectangular shape
  * @param h the height of the specified rectangular shape
  * @return <code>true</code> if the interior of this
  *                        <code>Polygon</code> and the interior of the
  *                        specified set of rectangular
  *                         coordinates intersect each other;
  *                        <code>false</code> otherwise.
  */
 public boolean intersects(double x, double y, double w, double h) {
     if (npoints <= 0 || !bounds.intersects(x, y, w, h)) {
         return false;
     }
     updateComputingPath();
     return closedPath.intersects(x, y, w, h);
 }
 /**
  * Tests if the interior of this <code>Polygon</code> intersects the
  * interior of a specified <code>Rectangle2D</code>.
  * @param r a specified <code>Rectangle2D</code>
  * @return <code>true</code> if this <code>Polygon</code> and the
  *                         interior of the specified <code>Rectangle2D</code>
  *                         intersect each other; <code>false</code>
  *                         otherwise.
  */
 public boolean intersects(Rectangle2D r) {
     return intersects(r.getX(), r.getY(), r.getWidth(), r.getHeight());
 }
 /**
  * Tests if the interior of this <code>Polygon</code> entirely
  * contains the specified set of rectangular coordinates.
  * @param x the x coordinate of the top-left corner of the
  *                         specified set of rectangular coordinates
  * @param y the y coordinate of the top-left corner of the
  *                         specified set of rectangular coordinates
  * @param w the width of the set of rectangular coordinates
  * @param h the height of the set of rectangular coordinates
  * @return <code>true</code> if this <code>Polygon</code> entirely
  *                         contains the specified set of rectangular
  *                         coordinates; <code>false</code> otherwise.
  */
 public boolean contains(double x, double y, double w, double h) {
     if (npoints <= 0 || !bounds.intersects(x, y, w, h)) {
         return false;
     }
     updateComputingPath();
     return closedPath.contains(x, y, w, h);
 }
 /**
  * Tests if the interior of this <code>Polygon</code> entirely
  * contains the specified <code>Rectangle2D</code>.
  * @param r the specified <code>Rectangle2D</code>
  * @return <code>true</code> if this <code>Polygon</code> entirely
  *                         contains the specified <code>Rectangle2D</code>;
  *                        <code>false</code> otherwise.
  * @see #contains(double, double, double, double)
  */
 public boolean contains(Rectangle2D r) {
     return contains(r.getX(), r.getY(), r.getWidth(), r.getHeight());
 }
 /**
  * Returns an iterator object that iterates along the boundary of this
  * <code>Polygon</code> and provides access to the geometry
  * of the outline of this <code>Polygon</code>.  An optional
  * {@link AffineTransform} can be specified so that the coordinates
  * returned in the iteration are transformed accordingly.
  * @param at an optional <code>AffineTransform</code> to be applied to the
  *                 coordinates as they are returned in the iteration, or
  *                <code>null</code> if untransformed coordinates are desired
  * @return a {@link PathIterator} object that provides access to the
  *                geometry of this <code>Polygon</code>.
  */
 public PathIterator getPathIterator(AffineTransform at) {
     updateComputingPath();
     if (closedPath == null) return null;
     else return closedPath.getPathIterator(at);
 }
 /**
  * Returns an iterator object that iterates along the boundary of
  * the <code>Polygon2D</code> and provides access to the geometry of the
  * outline of the <code>Shape</code>.  Only SEG_MOVETO, SEG_LINETO, and
  * SEG_CLOSE point types are returned by the iterator.
  * Since polygons are already flat, the <code>flatness</code> parameter
  * is ignored.
  * @param at an optional <code>AffineTransform</code> to be applied to the
  *                 coordinates as they are returned in the iteration, or
  *                <code>null</code> if untransformed coordinates are desired
  * @param flatness the maximum amount that the control points
  *                 for a given curve can vary from colinear before a subdivided
  *                curve is replaced by a straight line connecting the
  *                 endpoints.  Since polygons are already flat the
  *                 <code>flatness</code> parameter is ignored.
  * @return a <code>PathIterator</code> object that provides access to the
  *                 <code>Shape</code> object"s geometry.
  */
 public PathIterator getPathIterator(AffineTransform at, double flatness) {
     return getPathIterator(at);
 }
}



Reads a Point2D object that has been serialised by the writePoint2D(Point2D, ObjectOutputStream)} method.

   
import java.awt.geom.Point2D;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
 * 
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301, 
 * USA.  
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
 * in the United States and other countries.]
 * 
 * ------------
 * IOUtils.java
 * ------------
 * (C)opyright 2002-2004, by Thomas Morgner and Contributors.
 *
 * Original Author:  Thomas Morgner;
 * Contributor(s):   David Gilbert (for Object Refinery Limited);
 *
 * $Id: IOUtils.java,v 1.8 2009/01/22 08:34:58 taqua Exp $
 *
 * Changes
 * -------
 * 26-Jan-2003 : Initial version
 * 23-Feb-2003 : Documentation
 * 25-Feb-2003 : Fixed Checkstyle issues (DG);
 * 29-Apr-2003 : Moved to jcommon
 * 04-Jan-2004 : Fixed JDK 1.2.2 issues with createRelativeURL;
 *               added support for query strings within these urls (TM);
 */

public class Main {
  /**
   * Returns <code>true</code> if a class implements <code>Serializable</code>
   * and <code>false</code> otherwise.
   *
   * @param c  the class.
   *
   * @return A boolean.
   */
  public static boolean isSerializable(final Class c) {
      /**
      final Class[] interfaces = c.getInterfaces();
      for (int i = 0; i < interfaces.length; i++) {
          if (interfaces[i].equals(Serializable.class)) {
              return true;
          }
      }
      Class cc = c.getSuperclass();
      if (cc != null) {
          return isSerializable(cc);
      }
       */
      return (Serializable.class.isAssignableFrom(c));
  }
  /**
   * Reads a <code>Point2D</code> object that has been serialised by the
   * {@link #writePoint2D(Point2D, ObjectOutputStream)} method.
   *
   * @param stream  the input stream (<code>null</code> not permitted).
   *
   * @return The point object (possibly <code>null</code>).
   *
   * @throws IOException  if there is an I/O problem.
   */
  public static Point2D readPoint2D(final ObjectInputStream stream)
      throws IOException {
      if (stream == null) {
          throw new IllegalArgumentException("Null "stream" argument.");
      }
      Point2D result = null;
      final boolean isNull = stream.readBoolean();
      if (!isNull) {
          final double x = stream.readDouble();
          final double y = stream.readDouble();
          result = new Point2D.Double(x, y);
      }
      return result;
  }
  /**
   * Serialises a <code>Point2D</code> object.
   *
   * @param p  the point object (<code>null</code> permitted).
   * @param stream  the output stream (<code>null</code> not permitted).
   *
   * @throws IOException if there is an I/O error.
   */
  public static void writePoint2D(final Point2D p,
                                  final ObjectOutputStream stream)
      throws IOException {
      if (stream == null) {
          throw new IllegalArgumentException("Null "stream" argument.");
      }
      if (p != null) {
          stream.writeBoolean(false);
          stream.writeDouble(p.getX());
          stream.writeDouble(p.getY());
      }
      else {
          stream.writeBoolean(true);
      }
  }
}



Rectangle with rounded corners drawn using Java 2D Graphics API

    
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JFrame;
public class Main extends JFrame {
  public Main() {
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setSize(600, 600);
  }
  public void paint(Graphics g) {
    Graphics2D graphics2 = (Graphics2D) g;
    RoundRectangle2D roundedRectangle = new RoundRectangle2D.Float(10, 10, 240, 160, 10, 10);
    graphics2.draw(roundedRectangle);
  }
  public static void main(String args[]) {
    new Main().setVisible(true);
  }
}



RectListManager is a class to manage a list of rectangular regions.

   
/*
   Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed with
   this work for additional information regarding copyright ownership.
   The ASF licenses this file to You under the Apache License, Version 2.0
   (the "License"); you may not use this file except in compliance with
   the License.  You may obtain a copy of the License at
       http://www.apache.org/licenses/LICENSE-2.0
   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
import java.awt.Rectangle;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.ruparator;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.NoSuchElementException;
/**
 * RectListManager is a class to manage a list of rectangular regions.
 * This class contains methods to add new rectangles to the List, to
 * merge rectangles in the list (based on a cost function), and
 * functions to subract one RectListManager from another.  The main
 * purpose of this class is to manage dirty regions on a display (for
 * this reason it uses Rectangle not Rectangle2D).
 *
 * @author 
 * @version $Id: RectListManager.java 501844 2007-01-31 13:54:05Z dvholten $
 */
public class RectListManager implements Collection {
    Rectangle [] rects = null;
    int size = 0;
    Rectangle bounds = null;
    public void dump() {
        System.err.println("RLM: " + this + " Sz: " + size);
        System.err.println("Bounds: " + getBounds());
        for (int i=0; i<size; i++) {
            Rectangle r = rects[i];
            System.err.println("  [" + r.x + ", " + r.y + ", " +
                               r.width + ", " + r.height + "]" );
        }
    }
    /**
     * The comparator used to sort the elements of this List.
     * Sorts on x value of Rectangle.
     */
    public static Comparator comparator = new RectXComparator();
    /**
     * Construct a <tt>RectListManager</tt> from a Collection of Rectangles
     * @param rects Collection that must only contain rectangles.
     */
    public RectListManager(Collection rects) {
        this.rects = new Rectangle[rects.size()];
        Iterator i = rects.iterator();
        int j=0;
        while (i.hasNext())          // todo can be replaced by rects.toArray()
            this.rects[j++] = (Rectangle)i.next();
        this.size  = this.rects.length;

        Arrays.sort(this.rects, comparator);
    }
    /**
     * Construct a <tt>RectListManager</tt> from an Array of
     * <tt>Rectangles</tt>
     * @param rects Array of <tt>Rectangles</tt>, must not contain
     *              any null entries.
     */
    public RectListManager(Rectangle [] rects) {
        this(rects, 0, rects.length);
    }
    /**
     * Construct a <tt>RectListManager</tt> from an Array of
     * <tt>Rectangles</tt>
     * @param rects Array of <tt>Rectangles</tt>, must not contain
     *              any null entries in the range [off, off+sz-1].
     * @param off   The offset to start copying from in rects.
     * @param sz    The number of entries to copy from rects.
     */
    public RectListManager(Rectangle [] rects, int off, int sz) {
        this.size  = sz;
        this.rects = new Rectangle[sz];
        System.arraycopy(rects, off, this.rects, 0, sz);
        Arrays.sort(this.rects, comparator);
    }
    /**
     * Construct a <tt>RectListManager</tt> from another
     * <tt>RectListManager</tt> (data is copied).
     * @param rlm RectListManager to copy.
     */
    public RectListManager(RectListManager rlm) {
        this(rlm.rects);
    }
    /**
     * Construct a <tt>RectListManager</tt> with one rectangle
     * @param rect The rectangle to put in this rlm.
     */
    public RectListManager(Rectangle rect) {
        this();
        add(rect);
    }

    /**
     * Construct an initially empty <tt>RectListManager</tt>.
     */
    public RectListManager() {
        this.rects = new Rectangle[10];
        size = 0;
    }
    /**
     * Construct an initially empty <tt>RectListManager</tt>,
     * with initial <tt>capacity</tt>.
     * @param capacity The inital capacity for the list.  Setting
     *                 this appropriately can save reallocations.
     */
    public RectListManager(int capacity) {
        this.rects = new Rectangle[capacity];
    }
    public Rectangle getBounds() {
        if (bounds != null )
            return bounds;
        if (size == 0) return null;
        bounds = new Rectangle(rects[0]);
        for (int i=1; i< size; i++) {
            Rectangle r = rects[i];
            if (r.x < bounds.x) {
                bounds.width = bounds.x+bounds.width-r.x;
                bounds.x = r.x;
            }
            if (r.y < bounds.y) {
                bounds.height = bounds.y+bounds.height-r.y;
                bounds.y = r.y;
            }
            if (r.x+r.width > bounds.x+bounds.width)
                bounds.width = r.x+r.width-bounds.x;
            if (r.y+r.height > bounds.y+bounds.height)
                bounds.height = r.y+r.height-bounds.y;
        }
        return bounds;
    }
    /**
     * Standard <tt>Object</tt> clone method.
     */
    public Object clone() throws CloneNotSupportedException {
        return copy();
    }
    /**
     * Similar to clone only strongly typed
     */
    public RectListManager copy() {
        return new RectListManager(rects);
    }
    /**
     * Returns the number of elements currently stored in this collection.
     */
    public int size() { return size; }

    /**
     * Returns true if this collection contains no elements.
     */
    public boolean isEmpty() { return (size==0); }
    public void clear() {
        Arrays.fill( rects, null );
        size=0;
        bounds = null;
    }
    /**
     * Returns an iterator over the elements in this collection
     */
    public Iterator iterator() {
        return new RLMIterator();
    }
    /**
     * Returns a list iterator of the elements in this list
     * (in proper sequence).
     */
    public ListIterator listIterator() {
        return new RLMIterator();
    }
    public Object [] toArray() {
        Object [] ret = new Rectangle[size];
        System.arraycopy(rects, 0, ret, 0, size);
        return ret;
    }
    /**
     * fill the given array a with values from my internal <code>rects</code>.
     * when a is not large enough, a new array is allocated, filled and returned.
     * the method works only, when a is a Object[] or a Rectange[].
     * When this is not the case, the a[] is just cleared.
     *
     * @param a array to fill (must not be null!)
     * @return the content of rects, either in a[] or a fresh array.
     */
    public Object [] toArray(Object[] a) {
        Class t = a.getClass().getComponentType();
        if ((t != Object.class) &&
            (t != Rectangle.class)) {
            // Nothing here for it...
            Arrays.fill( a, null );
            return a;
        }
        if (a.length < size)
            a = new Rectangle[size];
        System.arraycopy(rects, 0, a, 0, size);
        Arrays.fill( a, size, a.length, null );
        return a;
    }
    public boolean add(Object o) {
        add((Rectangle)o);
        return true;
    }
    /**
     * Ensures that this collection contains the specified element
     * @param rect The rectangle to add
     */
    public void add(Rectangle rect) {
        add(rect, 0, size-1);
    }
    /**
     * Ensures that this collection contains the specified element
     * l is the lower bound index for insertion r is upper
     * bound index for insertion.
     * @param rect The rectangle to add
     * @param l the lowest possible index for a rect with
     *          greater "x" coord.
     * @param r the highest possible index for a rect with
     *          greater "x" coord.
     */
    protected void add(Rectangle rect, int l, int r) {
        ensureCapacity(size+1);
        int idx=l;
        while (l <= r) {
            idx = (l+r)/2;
            while ((rects[idx] == null) && (idx <r)) idx++;
            if (rects[idx] == null) {
                // All "null" from center to r so skip them
                r = (l+r)/2;
                idx = (l+r)/2;
                if (l>r)
                    idx=l;
                while ((rects[idx] == null) && (idx > l)) idx--;
                if (rects[idx] == null) {
                    rects[idx] = rect;
                    return;
                }
            }
            if (rect.x == rects[idx].x) break;
            if (rect.x <  rects[idx].x) {
                if (idx == 0) break;
                if ((rects[idx-1] != null) &&
                    (rect.x >= rects[idx-1].x)) break;
                r = idx-1;
            } else {
                if (idx == size-1)  {idx++; break; }
                if ((rects[idx+1] != null) &&
                    (rect.x <= rects[idx+1].x)) { idx++; break;}
                l = idx+1;
            }
        }
        if (idx < size) {
            System.arraycopy(rects, idx,
                             rects, idx+1, size-idx);
        }
        // if (idx!=0) System.out.print(rects[idx-1].x);
        // else System.out.print("[First]");
        // System.out.print(" " + rect.x + " ");
        // if (idx<size) System.out.print(rects[idx+1].x);
        // else System.out.print("[last]");
        // System.out.println("");
        rects[idx] = rect;
        size++;
        bounds=null;
    }
    public boolean addAll(Collection c) {
        if (c instanceof RectListManager) {
            add((RectListManager)c);
        } else {
            add(new RectListManager(c));
        }
        return (c.size() != 0);
    }
    public boolean contains(Object o) {
        Rectangle rect = (Rectangle)o;
        int l=0, r=size-1, idx=0;
        while (l <= r) {
            idx = (l+r) >>> 1;
            if (rect.x == rects[idx].x) break;
            if (rect.x <  rects[idx].x) {
                if (idx == 0) break;
                if (rect.x >= rects[idx-1].x) break;
                r = idx-1;
            } else {
                if (idx == size-1)  {idx++; break; }
                if (rect.x <= rects[idx+1].x) { idx++; break;}
                l = idx+1;
            }
        }
        // Didn"t find any rect with the same x value.
        if (rects[idx].x != rect.x) return false;
        // Search towards 0 from idx for rect that matches
        for (int i=idx; i>=0; i--){
            if (rects[idx].equals(rect)) return true;
            if (rects[idx].x != rect.x)  break;
        }
        // Search towards size from idx for rect that matches
        for (int i=idx+1; i<size; i++) {
            if (rects[idx].equals(rect)) return true;
            if (rects[idx].x != rect.x)  break;
        }
        // No match...
        return false;
    }
    /**
     * Returns true if this collection contains all of the elements in
     * the specified collection.
     */
    public boolean containsAll(Collection c) {
        if (c instanceof RectListManager)
            return containsAll((RectListManager)c);
        return containsAll(new RectListManager(c));
    }
    public boolean containsAll(RectListManager rlm) {
        int x, xChange = 0;
        for (int j=0, i=0; j<rlm.size; j++) {
            i=xChange;
            while(rects[i].x < rlm.rects[j].x) {
                i++;
                if (i == size) return false;
            }
            xChange = i;
            x = rects[i].x;
            while (!rlm.rects[j].equals(rects[i])) {
                i++;
                if (i == size) return false; // out of rects
                if (x != rects[i].x)
                    return false; // out of the zone.
            }
        }
        return true;
    }
    /**
     * Removes a single instance of the specified element from this
     * collection, if it is present.
     * @param o Object to remove an matching instance of.
     */
    public boolean remove(Object o) {
        return remove((Rectangle)o);
    }
    /**
     * Removes a single instance of the specified Rectangle from this
     * collection, if it is present.
     * @param rect Rectangle to remove an matching instance of.
     */
    public boolean remove(Rectangle rect) {
        int l=0, r=size-1, idx=0;
        while (l <= r) {
            idx = (l+r) >>> 1;
            if (rect.x == rects[idx].x) break;
            if (rect.x <  rects[idx].x) {
                if (idx == 0) break;
                if (rect.x >= rects[idx-1].x) break;
                r = idx-1;
            } else {
                if (idx == size-1)  {idx++; break; }
                if (rect.x <= rects[idx+1].x) { idx++; break;}
                l = idx+1;
            }
        }
        // Didn"t find any rect with the same x value.
        if (rects[idx].x != rect.x) return false;
        // Search towards 0 from idx for rect that matches
        for (int i=idx; i>=0; i--){
            if (rects[idx].equals(rect)) {
                System.arraycopy(rects, idx+1, rects, idx, size-idx);
                size--;
                bounds = null;
                return true;
            }
            if (rects[idx].x != rect.x)  break;
        }
        // Search towards size from idx for rect that matches
        for (int i=idx+1; i<size; i++) {
            if (rects[idx].equals(rect)) {
                System.arraycopy(rects, idx+1, rects, idx, size-idx);
                size--;
                bounds = null;
                return true;
            }
            if (rects[idx].x != rect.x)  break;
        }
        // No match...
        return false;
    }
    public boolean removeAll(Collection c) {
        if (c instanceof RectListManager)
            return removeAll((RectListManager)c);
        return removeAll(new RectListManager(c));
    }
    public boolean removeAll(RectListManager rlm) {
        int x, xChange = 0;
        boolean ret = false;
        for (int j=0, i=0; j<rlm.size; j++) {
            i=xChange;
            while ((rects[i] == null) ||
                   (rects[i].x < rlm.rects[j].x)) {
                i++;
                if (i == size) break;
            }
            if (i == size) break;
            xChange = i;
            x = rects[i].x;
            while (true) {
                if (rects[i] == null) {
                    i++;
                    if (i == size) break; // out of rects
                    continue;
                }
                if (rlm.rects[j].equals(rects[i])) {
                    rects[i] = null;
                    ret = true;
                }
                i++;
                if (i == size)       break; // out of rects
                if (x != rects[i].x) break; // out of the zone.
            }
        }
        // Now we will go through collapsing the nulled entries.
        if (ret) {
            int j=0, i=0;
            while (i<size) {
                if (rects[i] != null)
                    rects[j++] = rects[i];
                i++;
            }
            size = j;
            bounds = null;
        }
        return ret;
    }
    public boolean retainAll(Collection c) {
        if (c instanceof RectListManager)
            return retainAll((RectListManager)c);
        return retainAll(new RectListManager(c));
    }
    public boolean retainAll(RectListManager rlm) {
        int x, xChange = 0;
        boolean ret = false;
        for (int j=0, i=0; j<size; j++) {
            i=xChange;
            while (rlm.rects[i].x < rects[j].x) {
                i++;
                if (i == rlm.size) break;
            }
            if (i == rlm.size) {
                ret = true;
                // No more rects will match anything from rlm
                // so remove them from this RLM.
                for (int k=j; k<size; k++)
                    rects[k] = null;
                size = j;
                break;
            }
            xChange = i;
            x = rlm.rects[i].x;
            while (true) {
                if (rects[j].equals(rlm.rects[i])) break;
                i++;
                if ((i == rlm.size) ||
                    (x != rlm.rects[i].x)) {
                    // Out of zone or rects
                    rects[j] = null;
                    ret = true;
                    break;
                }
            }
        }
        // Now we will go through collapsing the nulled entries.
        if (ret) {
            int j=0, i=0;
            while (i<size) {
                if (rects[i] != null)
                    rects[j++] = rects[i];
                i++;
            }
            size = j;
            bounds = null;
        }
        return ret;
    }
    /**
     * Adds the contents of <tt>rlm</tt> to this RectListManager.  No
     * collapsing of rectangles is done here the contents are simply
     * added (you should generally call "mergeRects" some time after
     * this operation before using the contents of this
     * RectListManager.
     * @param rlm The RectListManager to add the contents of.  */
    public void add(RectListManager rlm) {
        if (rlm.size == 0)
            return;
        Rectangle [] dst = rects;
        if (rects.length < (size+rlm.size)) {
            dst = new Rectangle[size+rlm.size];
        }
        if (size == 0) {
            System.arraycopy(rlm.rects, 0, dst, size, rlm.size);
            size = rlm.size;
            bounds = null;
            return;
        }
        Rectangle [] src1   = rlm.rects;
        int          src1Sz = rlm.size;
        int          src1I  = src1Sz-1;
        Rectangle [] src2   = rects;
        int          src2Sz = size;
        int          src2I  = src2Sz-1;
        int dstI = size+rlm.size-1;
        int x1 = src1[src1I].x;
        int x2 = src2[src2I].x;
        while (dstI >= 0) {
            if (x1 <= x2) {
                dst[dstI] = src2[src2I];
                if (src2I == 0) {
                    System.arraycopy(src1, 0, dst, 0, src1I+1);
                    break;
                }
                src2I--;
                x2 = src2[src2I].x;
            } else {
                dst[dstI] = src1[src1I];
                if (src1I == 0) {
                    System.arraycopy(src2, 0, dst, 0, src2I+1);
                    break;
                }
                src1I--;
                x1 = src1[src1I].x;
            }
            dstI--;
        }
        rects = dst;
        size += rlm.size;
        bounds = null;
    }
    public void mergeRects(int overhead, int lineOverhead) {
        if (size == 0) return;
        Rectangle r, cr, mr;
        int cost1, cost2, cost3;
        mr = new Rectangle();
        Rectangle []splits = new Rectangle[4];
        for (int j, i=0; i<size; i++) {
            r = rects[i];
            if (r == null) continue;
            cost1 = (overhead                 +
                     (r.height*lineOverhead) +
                     (r.height*r.width));
            do {
                int maxX = r.x+r.width+overhead/r.height;
                for (j=i+1; j<size; j++) {
                    cr = rects[j];
                    if ((cr == null) || (cr == r)) continue;
                    if (cr.x >= maxX) {
                        // No more merges can happen.
                        j = size;
                        break;
                    }
                    cost2 = (overhead                 +
                             (cr.height*lineOverhead) +
                             (cr.height*cr.width));
                    mr = r.union(cr);
                    cost3 = (overhead                 +
                             (mr.height*lineOverhead) +
                             (mr.height*mr.width));
                    if (cost3 <= cost1+cost2) {
                        r = rects[i] = mr;
                        rects[j] = null;
                        cost1 = cost3;
                        j=-1;
                        break;
                    }
                    if (!r.intersects(cr)) continue;
                    splitRect(cr, r, splits);
                    int splitCost=0;
                    int l=0;
                    for (int k=0; k<4; k++) {
                        if (splits[k] != null) {
                            Rectangle sr = splits[k];
                            // Collapse null entries in first three
                            // (That share common "x").
                            if (k<3) splits[l++] = sr;
                            splitCost += (overhead                 +
                                          (sr.height*lineOverhead) +
                                          (sr.height*sr.width));
                        }
                    }
                    if (splitCost >= cost2) continue;
                    // Insert the splits.
                    if (l == 0) {
                        // only third split may be left (no common "x").
                        rects[j] = null;
                        if (splits[3] != null)
                            add(splits[3], j, size-1);
                        continue;
                    }
                    rects[j] = splits[0];
                    if (l > 1)
                        insertRects(splits, 1, j+1, l-1);
                    if (splits[3] != null)
                        add(splits[3], j, size-1);
                }
                // if we merged it with another rect then
                // we need to check all the rects up to i again,
                // against the merged rect.
            } while (j != size);
        }
        // Now we will go through collapsing the nulled entries.
        int j=0, i=0;
        float area=0;
        while (i<size) {
            if (rects[i] != null) {
                r = rects[i];
                rects[j++] = r;
                area += overhead + (r.height*lineOverhead) +
                    (r.height*r.width);
            }
            i++;
        }
        size = j;
        bounds=null;
        r = getBounds();
        if (r == null) return;
        if (overhead + (r.height*lineOverhead) + (r.height*r.width) < area) {
            rects[0] = r;
            size=1;
        }
    }
    public void subtract(RectListManager rlm, int overhead, int lineOverhead) {
        Rectangle r, sr;
        int cost;
        int jMin=0;
        Rectangle [] splits = new Rectangle[4];
        for(int i=0; i<size; i++) {
            r = rects[i]; // Canidate rect...
            cost = (overhead                +
                    (r.height*lineOverhead) +
                    (r.height*r.width));
            for (int j=jMin; j<rlm.size; j++) {
                sr = rlm.rects[j]; // subtraction rect.
                // Check if the canidate rect starts after
                // the end of this rect in "x" if so
                // go to the next one.
                if (sr.x+sr.width < r.x) {
                    // If this was jMin then increment jMin (no
                    // future canidate rect will intersect this rect).
                    if (j == jMin) jMin++;
                    continue;
                }
                // Check if the rest of the rects from rlm are past
                // the end of the canidate rect.  If so we are
                // done with this canidate rect.
                if (sr.x > r.x+r.width)
                    break;
                // If they don"t insersect then go to next sub rect.
                if (!r.intersects(sr))
                    continue;
                // Now we know they intersect one another lets
                // figure out how...
                splitRect(r, sr, splits);
                int splitCost=0;
                Rectangle tmpR;
                for (int k=0; k<4; k++) {
                    tmpR = splits[k];
                    if (tmpR != null)
                        splitCost += (overhead                   +
                                      (tmpR.height*lineOverhead) +
                                      (tmpR.height*tmpR.width));
                }
                if (splitCost >= cost)
                    // This isn"t ideal as depending on the order
                    // Stuff is done in we might later kill some of
                    // these rectangles (hence lowering the cost).
                    // For this reason it is probably best of the
                    // subtract list has been merged as this will help
                    // reduce the instances where this will happen.
                    continue;
                // Collapse null entries in first three elements
                // split 0, 1, 2 (entries that share a common "x").
                int l = 0;
                for (int k=0; k<3; k++) {
                    if (splits[k] != null)
                        splits[l++] = splits[k];
                }
                // Fully covered (or only split 3 survived which we
                // will visit later) this canidate rect goes away.
                if (l==0) {
                    rects[i].width = 0;
                    // Insert the third split (if any) at the
                    // proper place in rects list.
                    if (splits[3] != null)
                        add(splits[3], i, size-1);
                    break;
                }
                // Otherwise replace the canidate with the top of
                // the split, since it only shrunk it didn"t grow,
                // we know that the previous subtract rects don"t
                // intersect it.
                r        = splits[0];
                rects[i] = r;
                cost = (overhead                +
                        (r.height*lineOverhead) +
                        (r.height*r.width));
                // Add the remainder of the rects that
                // share "r.x" (if any).  Possible
                // are split 1, and split 2.
                if (l > 1)
                    insertRects(splits, 1, i+1, l-1);
                // Insert the third split (if any) at the
                // proper place in rects list.
                if (splits[3] != null)
                    add(splits[3], i+l, size-1);
            }
        }
        // Now we will go through collapsing the nulled entries.
        int j=0, i=0;
        while (i<size) {
            if (rects[i].width == 0)
                rects[i] = null;
            else
                rects[j++] = rects[i];
            i++;
        }
        size = j;
        bounds = null;
    }
    protected void splitRect(Rectangle r, Rectangle sr,
                             Rectangle []splits) {
        // We split the canidate rectrect into four parts.  In
        // many cases one or more of these will be empty.
        //
        //    +-------------------------------------+ ry0
        //    |                                     |
        //    |                                     |
        //    |          Split 0                    |
        //    |                                     |
        //    |                                     |
        // ------------+-----------------+--------------- sry0
        //    |        |                 |          |
        //    | Split2 |   subtracted    | Split 3  |
        //    |        |   rect          |          |
        //    |        |                 |          |
        // ------------+-----------------+--------------- sry1
        //    |       srx0              srx1        |
        //    |                                     |
        //    |          Split 1                    |
        //    |                                     |
        //    +-------------------------------------+ ry1
        //   rx0                                   rx1
        int rx0 = r.x;
        int rx1 = rx0+r.width-1;
        int ry0 = r.y;
        int ry1 = ry0+r.height-1;
        int srx0 = sr.x;
        int srx1 = srx0+sr.width-1;
        int sry0 = sr.y;
        int sry1 = sry0+sr.height-1;
        if ((ry0 < sry0) && (ry1 >= sry0)) {
            splits[0] = new Rectangle(rx0, ry0, r.width, sry0-ry0);
            ry0 = sry0;
        } else {
            splits[0] = null;
        }
        if ((ry0 <= sry1) && (ry1 > sry1)) {
            splits[1] = new Rectangle(rx0, sry1+1, r.width, ry1-sry1);
            ry1 = sry1;
        } else {
            splits[1] = null;
        }
        if ((rx0 < srx0) && (rx1 >= srx0)) {
            splits[2] = new Rectangle(rx0, ry0, srx0-rx0, ry1-ry0+1);
        } else {
            splits[2] = null;
        }
        if ((rx0 <= srx1) && (rx1 > srx1)) {
            splits[3]= new Rectangle(srx1+1, ry0, rx1-srx1, ry1-ry0+1);
        } else {
            splits[3] = null;
        }
    }
    protected void insertRects(Rectangle[] rects, int srcPos,
                               int dstPos, int len) {
        if (len == 0) return;
        // Make sure we have room.
        ensureCapacity(size+len);
        // Move everything after pos up...
        for (int i=size-1; i>=dstPos; i--)
            this.rects[i+len] = this.rects[i];
        // Put the new rects in.
        System.arraycopy( rects, srcPos, this.rects, dstPos, len );
        size += len;
    }
    public void ensureCapacity(int sz) {
        if (sz <= rects.length)
            return;
        int nSz = rects.length + (rects.length>>1) + 1;
        while (nSz < sz)
            nSz+=(nSz>>1)+1;
        Rectangle [] nRects = new Rectangle[nSz];
        System.arraycopy(rects, 0, nRects, 0, size);
        rects = nRects;
    }
    /**
     * Comparator for ordering rects in X.
     *
     * Note: this comparator imposes orderings that are inconsistent
     *       with equals.
     */
    private static class RectXComparator implements Comparator, Serializable {
        RectXComparator() { }
        public final int compare(Object o1, Object o2) {
            return ((Rectangle)o1).x-((Rectangle)o2).x;
        }
    }

    private class RLMIterator implements ListIterator {
        int idx = 0;
        boolean removeOk = false;
        boolean forward  = true;
        RLMIterator() { }
        public boolean hasNext() { return idx < size; }
        public int nextIndex() { return idx; }
        public Object next() {
            if (idx >= size)
                throw new NoSuchElementException("No Next Element");
            forward = true;
            removeOk = true;
            return rects[idx++];
        }
        public boolean hasPrevious() { return idx > 0; }
        public int previousIndex() { return idx-1; }
        public Object previous() {
            if (idx <= 0)
                throw new NoSuchElementException("No Previous Element");
            forward = false;
            removeOk = true;
            return rects[--idx];
        }
        public void remove() {
            if (!removeOk)
                throw new IllegalStateException
                    ("remove can only be called directly after next/previous");
            if (forward) idx--;
            if (idx != size-1)
                System.arraycopy(rects, idx+1, rects, idx, size-(idx+1));
            size--;
            rects[size] = null;
            removeOk = false;
        }

        public void set(Object o) {
            Rectangle r = (Rectangle)o;
            if (!removeOk)
                throw new IllegalStateException
                    ("set can only be called directly after next/previous");
            if (forward) idx--;
            if (idx+1<size) {
                if (rects[idx+1].x < r.x)
                    throw new UnsupportedOperationException
                        ("RectListManager entries must be sorted");
            }
            if (idx>=0) {
                if (rects[idx-1].x > r.x)
                    throw new UnsupportedOperationException
                        ("RectListManager entries must be sorted");
            }
            rects[idx] = r;
            removeOk = false;
        }
        public void add(Object o) {
            Rectangle r = (Rectangle)o;
            if (idx<size) {
                if (rects[idx].x < r.x)
                    throw new UnsupportedOperationException
                        ("RectListManager entries must be sorted");
            }
            if (idx!=0) {
                if (rects[idx-1].x > r.x)
                    throw new UnsupportedOperationException
                        ("RectListManager entries must be sorted");
            }
            ensureCapacity(size+1);
            if (idx != size)
                System.arraycopy(rects, idx, rects, idx+1, size-idx);
            rects[idx] = r;
            idx++;
            removeOk = false;
        }
    }
}



Resize a shape

     
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ResizeRectangle extends JPanel {
  private int SIZE = 8;
  private Rectangle2D[] points = { new Rectangle2D.Double(50, 50,SIZE, SIZE), new Rectangle2D.Double(150, 100,SIZE, SIZE) };
  Rectangle2D s = new Rectangle2D.Double();
  ShapeResizeHandler ada = new ShapeResizeHandler();
  public ResizeRectangle() {
    addMouseListener(ada);
    addMouseMotionListener(ada);
  }
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g;
    for (int i = 0; i < points.length; i++) {
      g2.fill(points[i]);
    }
    s.setRect(points[0].getCenterX(), points[0].getCenterY(),
        Math.abs(points[1].getCenterX()-points[0].getCenterX()),
        Math.abs(points[1].getCenterY()- points[0].getCenterY()));
    g2.draw(s);
  }
  class ShapeResizeHandler extends MouseAdapter {
    Rectangle2D r = new Rectangle2D.Double(0,0,SIZE,SIZE);
    private int pos = -1;
    public void mousePressed(MouseEvent event) {
      Point p = event.getPoint();
      for (int i = 0; i < points.length; i++) {
        if (points[i].contains(p)) {
          pos = i;
          return;
        }
      }
    }
    public void mouseReleased(MouseEvent event) {
      pos = -1;
    }
    public void mouseDragged(MouseEvent event) {
      if (pos == -1)
        return;
      points[pos].setRect(event.getPoint().x,event.getPoint().y,points[pos].getWidth(),
          points[pos].getHeight());
      repaint();
    }
  }
  public static void main(String[] args) {
    JFrame frame = new JFrame("Resize Rectangle");
    frame.add(new ResizeRectangle());
    frame.setSize(300, 300);
    frame.setLocationRelativeTo(null);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
  }
}



Returns a point based on (x, y) but constrained to be within the bounds of a given rectangle.

   
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
 *
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
 * in the United States and other countries.]
 *
 * -------------------
 * ShapeUtilities.java
 * -------------------
 * (C)opyright 2003-2008, by Object Refinery Limited and Contributors.
 *
 * Original Author:  David Gilbert (for Object Refinery Limited);
 * Contributor(s):   -;
 *
 * $Id: ShapeUtilities.java,v 1.18 2008/06/02 06:58:28 mungady Exp $
 *
 * Changes
 * -------
 * 13-Aug-2003 : Version 1 (DG);
 * 16-Mar-2004 : Moved rotateShape() from RefineryUtilities.java to here (DG);
 * 13-May-2004 : Added new shape creation methods (DG);
 * 30-Sep-2004 : Added createLineRegion() method (DG);
 *               Moved drawRotatedShape() method from RefineryUtilities class
 *               to this class (DG);
 * 04-Oct-2004 : Renamed ShapeUtils --> ShapeUtilities (DG);
 * 26-Oct-2004 : Added a method to test the equality of two Line2D
 *               instances (DG);
 * 10-Nov-2004 : Added new translateShape() and equal(Ellipse2D, Ellipse2D)
 *               methods (DG);
 * 11-Nov-2004 : Renamed translateShape() --> createTranslatedShape() (DG);
 * 07-Jan-2005 : Minor Javadoc fix (DG);
 * 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
 * 21-Jan-2005 : Modified return type of RectangleAnchor.coordinates()
 *               method (DG);
 * 22-Feb-2005 : Added equality tests for Arc2D and GeneralPath (DG);
 * 16-Mar-2005 : Fixed bug where equal(Shape, Shape) fails for two Polygon
 *               instances (DG);
 * 01-Jun-2008 : Fixed bug in equal(GeneralPath, GeneralPath) method (DG);
 *
 */
import java.awt.Shape;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
/**
 * Utility methods for {@link Shape} objects.
 *
 * @author David Gilbert
 */
public class Main {

  /**
   * Returns a point based on (x, y) but constrained to be within the bounds
   * of a given rectangle.
   *
   * @param x  the x-coordinate.
   * @param y  the y-coordinate.
   * @param area  the constraining rectangle (<code>null</code> not
   *              permitted).
   *
   * @return A point within the rectangle.
   *
   * @throws NullPointerException if <code>area</code> is <code>null</code>.
   */
  public static Point2D getPointInRectangle(double x, double y,
                                            final Rectangle2D area) {
      x = Math.max(area.getMinX(), Math.min(x, area.getMaxX()));
      y = Math.max(area.getMinY(), Math.min(y, area.getMaxY()));
      return new Point2D.Double(x, y);
  }
}



Serialises a Shape object.

   
import java.awt.Shape;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
 * 
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301, 
 * USA.  
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
 * in the United States and other countries.]
 * 
 * ------------
 * IOUtils.java
 * ------------
 * (C)opyright 2002-2004, by Thomas Morgner and Contributors.
 *
 * Original Author:  Thomas Morgner;
 * Contributor(s):   David Gilbert (for Object Refinery Limited);
 *
 * $Id: IOUtils.java,v 1.8 2009/01/22 08:34:58 taqua Exp $
 *
 * Changes
 * -------
 * 26-Jan-2003 : Initial version
 * 23-Feb-2003 : Documentation
 * 25-Feb-2003 : Fixed Checkstyle issues (DG);
 * 29-Apr-2003 : Moved to jcommon
 * 04-Jan-2004 : Fixed JDK 1.2.2 issues with createRelativeURL;
 *               added support for query strings within these urls (TM);
 */

public class Main {
  /**
   * Returns <code>true</code> if a class implements <code>Serializable</code>
   * and <code>false</code> otherwise.
   *
   * @param c  the class.
   *
   * @return A boolean.
   */
  public static boolean isSerializable(final Class c) {
      /**
      final Class[] interfaces = c.getInterfaces();
      for (int i = 0; i < interfaces.length; i++) {
          if (interfaces[i].equals(Serializable.class)) {
              return true;
          }
      }
      Class cc = c.getSuperclass();
      if (cc != null) {
          return isSerializable(cc);
      }
       */
      return (Serializable.class.isAssignableFrom(c));
  }
  /**
   * Reads a <code>Shape</code> object that has been serialised by the
   * {@link #writeShape(Shape, ObjectOutputStream)} method.
   *
   * @param stream  the input stream (<code>null</code> not permitted).
   *
   * @return The shape object (possibly <code>null</code>).
   *
   * @throws IOException  if there is an I/O problem.
   * @throws ClassNotFoundException  if there is a problem loading a class.
   */
  public static Shape readShape(final ObjectInputStream stream)
      throws IOException, ClassNotFoundException {
      if (stream == null) {
          throw new IllegalArgumentException("Null "stream" argument.");
      }
      Shape result = null;
      final boolean isNull = stream.readBoolean();
      if (!isNull) {
          final Class c = (Class) stream.readObject();
          if (c.equals(Line2D.class)) {
              final double x1 = stream.readDouble();
              final double y1 = stream.readDouble();
              final double x2 = stream.readDouble();
              final double y2 = stream.readDouble();
              result = new Line2D.Double(x1, y1, x2, y2);
          }
          else if (c.equals(Rectangle2D.class)) {
              final double x = stream.readDouble();
              final double y = stream.readDouble();
              final double w = stream.readDouble();
              final double h = stream.readDouble();
              result = new Rectangle2D.Double(x, y, w, h);
          }
          else if (c.equals(Ellipse2D.class)) {
              final double x = stream.readDouble();
              final double y = stream.readDouble();
              final double w = stream.readDouble();
              final double h = stream.readDouble();
              result = new Ellipse2D.Double(x, y, w, h);
          }
          else if (c.equals(Arc2D.class)) {
              final double x = stream.readDouble();
              final double y = stream.readDouble();
              final double w = stream.readDouble();
              final double h = stream.readDouble();
              final double as = stream.readDouble(); // Angle Start
              final double ae = stream.readDouble(); // Angle Extent
              final int at = stream.readInt();       // Arc type
              result = new Arc2D.Double(x, y, w, h, as, ae, at);
          }
          else if (c.equals(GeneralPath.class)) {
              final GeneralPath gp = new GeneralPath();
              final float[] args = new float[6];
              boolean hasNext = stream.readBoolean();
              while (!hasNext) {
                  final int type = stream.readInt();
                  for (int i = 0; i < 6; i++) {
                      args[i] = stream.readFloat();
                  }
                  switch (type) {
                      case PathIterator.SEG_MOVETO :
                          gp.moveTo(args[0], args[1]);
                          break;
                      case PathIterator.SEG_LINETO :
                          gp.lineTo(args[0], args[1]);
                          break;
                      case PathIterator.SEG_CUBICTO :
                          gp.curveTo(args[0], args[1], args[2],
                                  args[3], args[4], args[5]);
                          break;
                      case PathIterator.SEG_QUADTO :
                          gp.quadTo(args[0], args[1], args[2], args[3]);
                          break;
                      case PathIterator.SEG_CLOSE :
                          gp.closePath();
                          break;
                      default :
                          throw new RuntimeException(
                                  "JFreeChart - No path exists");
                  }
                  gp.setWindingRule(stream.readInt());
                  hasNext = stream.readBoolean();
              }
              result = gp;
          }
          else {
              result = (Shape) stream.readObject();
          }
      }
      return result;
  }
  /**
   * Serialises a <code>Shape</code> object.
   *
   * @param shape  the shape object (<code>null</code> permitted).
   * @param stream  the output stream (<code>null</code> not permitted).
   *
   * @throws IOException if there is an I/O error.
   */
  public static void writeShape(final Shape shape,
                                final ObjectOutputStream stream)
      throws IOException {
      if (stream == null) {
          throw new IllegalArgumentException("Null "stream" argument.");
      }
      if (shape != null) {
          stream.writeBoolean(false);
          if (shape instanceof Line2D) {
              final Line2D line = (Line2D) shape;
              stream.writeObject(Line2D.class);
              stream.writeDouble(line.getX1());
              stream.writeDouble(line.getY1());
              stream.writeDouble(line.getX2());
              stream.writeDouble(line.getY2());
          }
          else if (shape instanceof Rectangle2D) {
              final Rectangle2D rectangle = (Rectangle2D) shape;
              stream.writeObject(Rectangle2D.class);
              stream.writeDouble(rectangle.getX());
              stream.writeDouble(rectangle.getY());
              stream.writeDouble(rectangle.getWidth());
              stream.writeDouble(rectangle.getHeight());
          }
          else if (shape instanceof Ellipse2D) {
              final Ellipse2D ellipse = (Ellipse2D) shape;
              stream.writeObject(Ellipse2D.class);
              stream.writeDouble(ellipse.getX());
              stream.writeDouble(ellipse.getY());
              stream.writeDouble(ellipse.getWidth());
              stream.writeDouble(ellipse.getHeight());
          }
          else if (shape instanceof Arc2D) {
              final Arc2D arc = (Arc2D) shape;
              stream.writeObject(Arc2D.class);
              stream.writeDouble(arc.getX());
              stream.writeDouble(arc.getY());
              stream.writeDouble(arc.getWidth());
              stream.writeDouble(arc.getHeight());
              stream.writeDouble(arc.getAngleStart());
              stream.writeDouble(arc.getAngleExtent());
              stream.writeInt(arc.getArcType());
          }
          else if (shape instanceof GeneralPath) {
              stream.writeObject(GeneralPath.class);
              final PathIterator pi = shape.getPathIterator(null);
              final float[] args = new float[6];
              stream.writeBoolean(pi.isDone());
              while (!pi.isDone()) {
                  final int type = pi.currentSegment(args);
                  stream.writeInt(type);
                  // TODO: could write this to only stream the values
                  // required for the segment type
                  for (int i = 0; i < 6; i++) {
                      stream.writeFloat(args[i]);
                  }
                  stream.writeInt(pi.getWindingRule());
                  pi.next();
                  stream.writeBoolean(pi.isDone());
              }
          }
          else {
              stream.writeObject(shape.getClass());
              stream.writeObject(shape);
          }
      }
      else {
          stream.writeBoolean(true);
      }
  }
}



Shape combine

     
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class CombiningShapes extends JComponent {
  private Shape mShapeOne, mShapeTwo;
  private JComboBox mOptions;
  public CombiningShapes() {
    mShapeOne = new Ellipse2D.Double(40, 20, 80, 80);
    mShapeTwo = new Rectangle2D.Double(60, 40, 80, 80);
    setBackground(Color.white);
    setLayout(new BorderLayout());
    JPanel controls = new JPanel();
    mOptions = new JComboBox(new String[] { "outline", "add",
        "intersection", "subtract", "exclusive or" });
    mOptions.addItemListener(new ItemListener() {
      public void itemStateChanged(ItemEvent ie) {
        repaint();
      }
    });
    controls.add(mOptions);
    add(controls, BorderLayout.SOUTH);
  }
  public void paintComponent(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    String option = (String) mOptions.getSelectedItem();
    if (option.equals("outline")) {
      // draw the outlines and return.
      g2.draw(mShapeOne);
      g2.draw(mShapeTwo);
      return;
    }
    // Create Areas from the shapes.
    Area areaOne = new Area(mShapeOne);
    Area areaTwo = new Area(mShapeTwo);
    // Combine the Areas according to the selected option.
    if (option.equals("add"))
      areaOne.add(areaTwo);
    else if (option.equals("intersection"))
      areaOne.intersect(areaTwo);
    else if (option.equals("subtract"))
      areaOne.subtract(areaTwo);
    else if (option.equals("exclusive or"))
      areaOne.exclusiveOr(areaTwo);
    // Fill the resulting Area.
    g2.setPaint(Color.orange);
    g2.fill(areaOne);
    // Draw the outline of the resulting Area.
    g2.setPaint(Color.black);
    g2.draw(areaOne);
  }
  public static void main(String[] args) {
    JFrame f = new JFrame();
    f.add(new CombiningShapes());
    f.setSize(220, 220);
    f.setVisible(true);
  }
  
}



Tests two polygons for equality. If both are null this method returns true.

   
import java.awt.Polygon;
import java.util.Arrays;
public class Main {
  /**
   * Tests two polygons for equality.  If both are <code>null</code> this
   * method returns <code>true</code>.
   *
   * @param p1  polygon 1 (<code>null</code> permitted).
   * @param p2  polygon 2 (<code>null</code> permitted).
   *
   * @return A boolean.
   */
  public static boolean equal(final Polygon p1, final Polygon p2) {
      if (p1 == null) {
          return (p2 == null);
      }
      if (p2 == null) {
          return false;
      }
      if (p1.npoints != p2.npoints) {
          return false;
      }
      if (!Arrays.equals(p1.xpoints, p2.xpoints)) {
          return false;
      }
      if (!Arrays.equals(p1.ypoints, p2.ypoints)) {
          return false;
      }
      return true;
  }
}



Union two rectangles

    
/*
 * $Id: RectUtils.java,v 1.2 2008/02/28 14:38:48 david Exp $
 *
 * Copyright (c) 2008 Gaudenz Alder
 *
 */

import java.awt.geom.Rectangle2D;
public class RectUtils {
  /**
   * Unions the pair of source <code>Rectangle2D</code> objects and puts the
   * result into the returned <code>Rectangle2D</code> object. This method
   * extends the Rectangle2D version by checking for null parameters, the
   * returned value will also be <code>null</code> if the two input
   * rectangles are <code>null</code>
   * 
   * @param src1
   *            the first of a pair of <code>Rectangle2D</code> objects to
   *            be combined with each other
   * @param src2
   *            the second of a pair of <code>Rectangle2D</code> objects to
   *            be combined with each other
   * 
   */
  public static Rectangle2D union(Rectangle2D src1, Rectangle2D src2) {
    Rectangle2D result = null;
    if (src1 == null && src2 == null) {
      result = null;
    } else if (src1 != null && src2 != null) {
      double x1 = Math.min(src1.getMinX(), src2.getMinX());
      double y1 = Math.min(src1.getMinY(), src2.getMinY());
      double x2 = Math.max(src1.getMaxX(), src2.getMaxX());
      double y2 = Math.max(src1.getMaxY(), src2.getMaxY());
      result = new Rectangle2D.Double();
      result.setFrameFromDiagonal(x1, y1, x2, y2);
    } else if (src1 != null) {
      double x1 = src1.getMinX();
      double y1 = src1.getMinY();
      double x2 = src1.getMaxX();
      double y2 = src1.getMaxY();
      result = new Rectangle2D.Double();
      result.setFrameFromDiagonal(x1, y1, x2, y2);
    } else {
      // only src2 is non-null
      double x1 = src2.getMinX();
      double y1 = src2.getMinY();
      double x2 = src2.getMaxX();
      double y2 = src2.getMaxY();
      result = new Rectangle2D.Double();
      result.setFrameFromDiagonal(x1, y1, x2, y2);
    }
    return result;
  }
}