Java/2D Graphics GUI/Stroke

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

A component for choosing a stroke from a list of available strokes.

  
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2009, 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.]
 *
 * -----------------------
 * StrokeChooserPanel.java
 * -----------------------
 * (C) Copyright 2000-2009, by Object Refinery Limited.
 *
 * Original Author:  David Gilbert (for Object Refinery Limited);
 * Contributor(s):   Dirk Zeitz;
 *
 * $Id: StrokeChooserPanel.java,v 1.8 2009/02/27 13:58:41 mungady Exp $
 *
 * Changes (from 26-Oct-2001)
 * --------------------------
 * 26-Oct-2001 : Changed package to com.jrefinery.ui.*;
 * 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
 * 16-Mar-2004 : Fix for focus problems (DZ);
 * 27-Feb-2009 : Fixed bug 2612649, NullPointerException (DG);
 *
 */

import java.awt.BorderLayout;
import java.awt.ruponent;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
/**
 * A component for choosing a stroke from a list of available strokes.
 *
 * @author David Gilbert
 */
public class StrokeChooserPanel extends JPanel {
    /** A combo for selecting the stroke. */
    private JComboBox selector;
    /**
     * Creates a panel containing a combo-box that allows the user to select
     * one stroke from a list of available strokes.
     *
     * @param current  the current stroke sample.
     * @param available  an array of "available" stroke samples.
     */
    public StrokeChooserPanel(StrokeSample current, StrokeSample[] available) {
        setLayout(new BorderLayout());
        // we"ve changed the behaviour here to populate the combo box
        // with Stroke objects directly - ideally we"d change the signature
        // of the constructor too...maybe later.
        DefaultComboBoxModel model = new DefaultComboBoxModel();
        for (int i = 0; i < available.length; i++) {
            model.addElement(available[i].getStroke());
        }
        this.selector = new JComboBox(model);
        this.selector.setSelectedItem(current.getStroke());
        this.selector.setRenderer(new StrokeSample(null));
        add(this.selector);
        // Changes due to focus problems!! DZ
        this.selector.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent evt) {
                getSelector().transferFocus();
            }
        });
    }

    /**
     * Returns the selector component.
     *
     * @return Returns the selector.
     */
    protected final JComboBox getSelector() {
        return this.selector;
    }
    /**
     * Returns the selected stroke.
     *
     * @return The selected stroke (possibly <code>null</code>).
     */
    public Stroke getSelectedStroke() {
        return (Stroke) this.selector.getSelectedItem();
    }
}
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2009, 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.]
 *
 * -----------------
 * StrokeSample.java
 * -----------------
 * (C) Copyright 2000-2009, by Object Refinery Limited.
 *
 * Original Author:  David Gilbert (for Object Refinery Limited);
 * Contributor(s):   -;
 *
 * $Id: StrokeSample.java,v 1.5 2009/02/27 13:58:41 mungady Exp $
 *
 * Changes (from 26-Oct-2001)
 * --------------------------
 * 26-Oct-2001 : Changed package to com.jrefinery.ui.*;
 * 14-Oct-2002 : Fixed errors reported by Checkstyle (DG);
 * 21-Mar-2003 : Fixed null pointer exception, bug 705126 (DG);
 *
 */

/**
 * A panel that displays a stroke sample.
 *
 * @author David Gilbert
 */
 class StrokeSample extends JComponent implements ListCellRenderer {
    /** The stroke being displayed (may be null). */
    private Stroke stroke;
    /** The preferred size of the component. */
    private Dimension preferredSize;
    /**
     * Creates a StrokeSample for the specified stroke.
     *
     * @param stroke  the sample stroke (<code>null</code> permitted).
     */
    public StrokeSample(final Stroke stroke) {
        this.stroke = stroke;
        this.preferredSize = new Dimension(80, 18);
        setPreferredSize(this.preferredSize);
    }
    /**
     * Returns the current Stroke object being displayed.
     *
     * @return The stroke (possibly <code>null</code>).
     */
    public Stroke getStroke() {
        return this.stroke;
    }
    /**
     * Sets the stroke object being displayed and repaints the component.
     *
     * @param stroke  the stroke (<code>null</code> permitted).
     */
    public void setStroke(final Stroke stroke) {
        this.stroke = stroke;
        repaint();
    }
    /**
     * Returns the preferred size of the component.
     *
     * @return the preferred size of the component.
     */
    public Dimension getPreferredSize() {
        return this.preferredSize;
    }
    /**
     * Draws a line using the sample stroke.
     *
     * @param g  the graphics device.
     */
    public void paintComponent(final Graphics g) {
        final Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        final Dimension size = getSize();
        final Insets insets = getInsets();
        final double xx = insets.left;
        final double yy = insets.top;
        final double ww = size.getWidth() - insets.left - insets.right;
        final double hh = size.getHeight() - insets.top - insets.bottom;
        // calculate point one
        final Point2D one =  new Point2D.Double(xx + 6, yy + hh / 2);
        // calculate point two
        final Point2D two =  new Point2D.Double(xx + ww - 6, yy + hh / 2);
        // draw a circle at point one
        final Ellipse2D circle1 = new Ellipse2D.Double(one.getX() - 5,
                one.getY() - 5, 10, 10);
        final Ellipse2D circle2 = new Ellipse2D.Double(two.getX() - 6,
                two.getY() - 5, 10, 10);
        // draw a circle at point two
        g2.draw(circle1);
        g2.fill(circle1);
        g2.draw(circle2);
        g2.fill(circle2);
        // draw a line connecting the points
        final Line2D line = new Line2D.Double(one, two);
        if (this.stroke != null) {
            g2.setStroke(this.stroke);
            g2.draw(line);
        }
    }
    /**
     * Returns a list cell renderer for the stroke, so the sample can be
     * displayed in a list or combo.
     *
     * @param list  the list.
     * @param value  the value.
     * @param index  the index.
     * @param isSelected  selected?
     * @param cellHasFocus  focussed?
     *
     * @return the component for rendering.
     */
    public Component getListCellRendererComponent(JList list, Object value,
            int index, boolean isSelected, boolean cellHasFocus) {
        if (value instanceof Stroke) {
            setStroke((Stroke) value);
        }
        else {
            setStroke(null);
        }
        return this;
    }
}



A dashed stroke

     

import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class BasicDraw {
  public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.add(new MyComponent());
    frame.setSize(300, 300);
    frame.setVisible(true);
  }
}
class MyComponent extends JComponent {
  public void paint(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;
    float strokeThickness = 5.0f;
    float miterLimit = 10f;
    float[] dashPattern = { 10f };
    float dashPhase = 5f;
    BasicStroke stroke = new BasicStroke(strokeThickness, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
        miterLimit, dashPattern, dashPhase);
    g2d.setStroke(stroke);
    g2d.draw(new Rectangle(20,20,200,200));
  }
}



Basic stroke

     
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class BasicStrokeDemo extends JPanel {
  public void init() {
    setBackground(Color.white);
  }
  public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    g2.setStroke(new BasicStroke(3.0f));
    g2.setPaint(Color.blue);
    
    Rectangle r = new Rectangle(5,5,200,200);
    
    g2.draw(r);
  }
  public static void main(String s[]) {
    JFrame f = new JFrame();
    f.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    BasicStrokeDemo p = new BasicStrokeDemo();
    f.getContentPane().add("Center", p);
    p.init();
    f.pack();
    f.setSize(new Dimension(250, 250));
    f.show();
  }
}



Cancel the effects of the zoom on a particular Stroke

    
/*
 * Java2DUtils.java
 * 
 * Created on Aug 30, 2007, 11:40:18 AM
 * 
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
//Revised from jaspersoft ireport designer
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.util.Stack;
/**
 *
 * @author gtoffoli
 */
public class Java2DUtils
{
  /**
   * This function provides a way to cancel the effects of the zoom on a particular Stroke.
   * All the stroke values (as line width, dashes, etc...) are divided by the zoom factor.
   * This allow to have essentially a fixed Stroke independent by the zoom.
   * The returned Stroke is a copy.
   * Remember to restore the right stroke in the graphics when done.
   * 
   * It works only with instances of BasicStroke
   * 
   * zoom is the zoom factor.
   */
  public static Stroke getInvertedZoomedStroke(Stroke stroke, double zoom)
  {
            if (stroke == null || !(stroke instanceof BasicStroke )) return stroke;
            
            BasicStroke bs = (BasicStroke)stroke;
            float[] dashArray = bs.getDashArray();
            
            float[] newDashArray = null;
            if (dashArray != null)
            {
                newDashArray = new float[dashArray.length];
                for (int i=0; i<newDashArray.length; ++i)
                {
                    newDashArray[i] = (float)(dashArray[i] / zoom);
                }
            }
            
            BasicStroke newStroke = new BasicStroke(       
                            (float)(bs.getLineWidth() / zoom),
                            bs.getEndCap(),
                            bs.getLineJoin(),
                            bs.getMiterLimit(),
                            //(float)(bs.getMiterLimit() / zoom),
                            newDashArray,
                            (float)(bs.getDashPhase() / zoom)
                    );
            return newStroke;
  }
}



Changing the Thickness of the Stroking Pen

     
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class BasicDraw {
  public static void main(String[] args) {
    new BasicDraw();
  }
  BasicDraw() {
    JFrame frame = new JFrame();
    frame.add(new MyComponent());
    frame.setSize(300, 300);
    frame.setVisible(true);
  }
}
class MyComponent extends JComponent {
  public void paint(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;
    float strokeThickness = 5.0f;
    BasicStroke stroke = new BasicStroke(strokeThickness);
    g2d.setStroke(stroke);
    g2d.draw(new Rectangle(20,20,200,200));
  }
}



Custom Strokes

     
/*
 * Copyright (c) 2000 David Flanagan.  All rights reserved.
 * This code is from the book Java Examples in a Nutshell, 2nd Edition.
 * It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
 * You may study, use, and modify it for any non-commercial purpose.
 * You may distribute it non-commercially as long as you retain this notice.
 * For a commercial use license, or to purchase the book (recommended),
 * visit http://www.davidflanagan.ru/javaexamples2.
 */
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.font.GlyphVector;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
/** A demonstration of writing custom Stroke classes */
public class CustomStrokes extends JPanel{
  static final int WIDTH = 750, HEIGHT = 200; // Size of our example
  public String getName() {
    return "Custom Strokes";
  }
  public int getWidth() {
    return WIDTH;
  }
  public int getHeight() {
    return HEIGHT;
  }
  // These are the various stroke objects we"ll demonstrate
  Stroke[] strokes = new Stroke[] { new BasicStroke(4.0f), // The standard,
      // predefined
      // stroke
      new NullStroke(), // A Stroke that does nothing
      new DoubleStroke(8.0f, 2.0f), // A Stroke that strokes twice
      new ControlPointsStroke(2.0f), // Shows the vertices & control
      // points
      new SloppyStroke(2.0f, 3.0f) // Perturbs the shape before stroking
  };
  /** Draw the example */
  public void paint(Graphics g1) {
    Graphics2D g = (Graphics2D)g1;
    // Get a shape to work with. Here we"ll use the letter B
    Font f = new Font("Serif", Font.BOLD, 200);
    GlyphVector gv = f.createGlyphVector(g.getFontRenderContext(), "B");
    Shape shape = gv.getOutline();
    // Set drawing attributes and starting position
    g.setColor(Color.black);
    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    g.translate(10, 175);
    // Draw the shape once with each stroke
    for (int i = 0; i < strokes.length; i++) {
      g.setStroke(strokes[i]); // set the stroke
      g.draw(shape); // draw the shape
      g.translate(140, 0); // move to the right
    }
  }
  public static void main(String[] a) {
    JFrame f = new JFrame();
    f.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    f.setContentPane(new CustomStrokes());
    f.setSize(750,200);
    f.setVisible(true);
  }
}
/**
 * This Stroke implementation does nothing. Its createStrokedShape() method
 * returns an unmodified shape. Thus, drawing a shape with this Stroke is the
 * same as filling that shape!
 */
class NullStroke implements Stroke {
  public Shape createStrokedShape(Shape s) {
    return s;
  }
}
/**
 * This Stroke implementation applies a BasicStroke to a shape twice. If you
 * draw with this Stroke, then instead of outlining the shape, you"re outlining
 * the outline of the shape.
 */
class DoubleStroke implements Stroke {
  BasicStroke stroke1, stroke2; // the two strokes to use
  public DoubleStroke(float width1, float width2) {
    stroke1 = new BasicStroke(width1); // Constructor arguments specify
    stroke2 = new BasicStroke(width2); // the line widths for the strokes
  }
  public Shape createStrokedShape(Shape s) {
    // Use the first stroke to create an outline of the shape
    Shape outline = stroke1.createStrokedShape(s);
    // Use the second stroke to create an outline of that outline.
    // It is this outline of the outline that will be filled in
    return stroke2.createStrokedShape(outline);
  }
}
/**
 * This Stroke implementation strokes the shape using a thin line, and also
 * displays the end points and Bezier curve control points of all the line and
 * curve segments that make up the shape. The radius argument to the constructor
 * specifies the size of the control point markers. Note the use of PathIterator
 * to break the shape down into its segments, and of GeneralPath to build up the
 * stroked shape.
 */
class ControlPointsStroke implements Stroke {
  float radius; // how big the control point markers should be
  public ControlPointsStroke(float radius) {
    this.radius = radius;
  }
  public Shape createStrokedShape(Shape shape) {
    // Start off by stroking the shape with a thin line. Store the
    // resulting shape in a GeneralPath object so we can add to it.
    GeneralPath strokedShape = new GeneralPath(new BasicStroke(1.0f)
        .createStrokedShape(shape));
    // Use a PathIterator object to iterate through each of the line and
    // curve segments of the shape. For each one, mark the endpoint and
    // control points (if any) by adding a rectangle to the GeneralPath
    float[] coords = new float[6];
    for (PathIterator i = shape.getPathIterator(null); !i.isDone(); i
        .next()) {
      int type = i.currentSegment(coords);
      Shape s = null, s2 = null, s3 = null;
      switch (type) {
      case PathIterator.SEG_CUBICTO:
        markPoint(strokedShape, coords[4], coords[5]); // falls through
      case PathIterator.SEG_QUADTO:
        markPoint(strokedShape, coords[2], coords[3]); // falls through
      case PathIterator.SEG_MOVETO:
      case PathIterator.SEG_LINETO:
        markPoint(strokedShape, coords[0], coords[1]); // falls through
      case PathIterator.SEG_CLOSE:
        break;
      }
    }
    return strokedShape;
  }
  /** Add a small square centered at (x,y) to the specified path */
  void markPoint(GeneralPath path, float x, float y) {
    path.moveTo(x - radius, y - radius); // Begin a new sub-path
    path.lineTo(x + radius, y - radius); // Add a line segment to it
    path.lineTo(x + radius, y + radius); // Add a second line segment
    path.lineTo(x - radius, y + radius); // And a third
    path.closePath(); // Go back to last moveTo position
  }
}
/**
 * This Stroke implementation randomly perturbs the line and curve segments that
 * make up a Shape, and then strokes that perturbed shape. It uses PathIterator
 * to loop through the Shape and GeneralPath to build up the modified shape.
 * Finally, it uses a BasicStroke to stroke the modified shape. The result is a
 * "sloppy" looking shape.
 */
class SloppyStroke implements Stroke {
  BasicStroke stroke;
  float sloppiness;
  public SloppyStroke(float width, float sloppiness) {
    this.stroke = new BasicStroke(width); // Used to stroke modified shape
    this.sloppiness = sloppiness; // How sloppy should we be?
  }
  public Shape createStrokedShape(Shape shape) {
    GeneralPath newshape = new GeneralPath(); // Start with an empty shape
    // Iterate through the specified shape, perturb its coordinates, and
    // use them to build up the new shape.
    float[] coords = new float[6];
    for (PathIterator i = shape.getPathIterator(null); !i.isDone(); i
        .next()) {
      int type = i.currentSegment(coords);
      switch (type) {
      case PathIterator.SEG_MOVETO:
        perturb(coords, 2);
        newshape.moveTo(coords[0], coords[1]);
        break;
      case PathIterator.SEG_LINETO:
        perturb(coords, 2);
        newshape.lineTo(coords[0], coords[1]);
        break;
      case PathIterator.SEG_QUADTO:
        perturb(coords, 4);
        newshape.quadTo(coords[0], coords[1], coords[2], coords[3]);
        break;
      case PathIterator.SEG_CUBICTO:
        perturb(coords, 6);
        newshape.curveTo(coords[0], coords[1], coords[2], coords[3],
            coords[4], coords[5]);
        break;
      case PathIterator.SEG_CLOSE:
        newshape.closePath();
        break;
      }
    }
    // Finally, stroke the perturbed shape and return the result
    return stroke.createStrokedShape(newshape);
  }
  // Randomly modify the specified number of coordinates, by an amount
  // specified by the sloppiness field.
  void perturb(float[] coords, int numCoords) {
    for (int i = 0; i < numCoords; i++)
      coords[i] += (float) ((Math.random() * 2 - 1.0) * sloppiness);
  }
}



Dashed rectangle

     
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 DashedRectangleDemo2D extends JApplet {
  final static float dash1[] = { 10.0f };
  final static BasicStroke dashed = new BasicStroke(1.0f,
      BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash1, 0.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(dashed);
    g2.draw(new RoundRectangle2D.Double(x, y, 200, 200,
            10, 10));
    g2.drawString("RoundRectangle2D", 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 DashedRectangleDemo2D();
    f.getContentPane().add("Center", applet);
    applet.init();
    f.pack();
    f.setSize(new Dimension(300, 300));
    f.show();
  }
}



Dashed stroke

     
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DashedStrokeDemo extends JPanel {
  public void init() {
    setBackground(Color.white);
  }
  public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    float dash[] = { 10.0f };
    g2.setStroke(new BasicStroke(3.0f, BasicStroke.CAP_BUTT,
        BasicStroke.JOIN_MITER, 10.0f, dash, 0.0f));
    g2.setPaint(Color.blue);
    
    Rectangle r = new Rectangle(5,5,200,200);
    
    g2.draw(r);
  }
  public static void main(String s[]) {
    JFrame f = new JFrame();
    f.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    DashedStrokeDemo p = new DashedStrokeDemo();
    f.getContentPane().add("Center", p);
    p.init();
    f.pack();
    f.setSize(new Dimension(250, 250));
    f.show();
  }
}



Serialises a Stroke object

 

import java.awt.BasicStroke;
import java.awt.Stroke;
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>Stroke</code> object that has been serialised by the
   * {@link SerialUtilities#writeStroke(Stroke, ObjectOutputStream)} method.
   *
   * @param stream  the input stream (<code>null</code> not permitted).
   *
   * @return The stroke 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 Stroke readStroke(final ObjectInputStream stream)
      throws IOException, ClassNotFoundException {
      if (stream == null) {
          throw new IllegalArgumentException("Null "stream" argument.");
      }
      Stroke result = null;
      final boolean isNull = stream.readBoolean();
      if (!isNull) {
          final Class c = (Class) stream.readObject();
          if (c.equals(BasicStroke.class)) {
              final float width = stream.readFloat();
              final int cap = stream.readInt();
              final int join = stream.readInt();
              final float miterLimit = stream.readFloat();
              final float[] dash = (float[]) stream.readObject();
              final float dashPhase = stream.readFloat();
              result = new BasicStroke(
                  width, cap, join, miterLimit, dash, dashPhase
              );
          }
          else {
              result = (Stroke) stream.readObject();
          }
      }
      return result;
  }
  /**
   * Serialises a <code>Stroke</code> object.  This code handles the
   * <code>BasicStroke</code> class which is the only <code>Stroke</code>
   * implementation provided by the JDK (and isn"t directly
   * <code>Serializable</code>).
   *
   * @param stroke  the stroke 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 writeStroke(final Stroke stroke,
                                 final ObjectOutputStream stream)
      throws IOException {
      if (stream == null) {
          throw new IllegalArgumentException("Null "stream" argument.");
      }
      if (stroke != null) {
          stream.writeBoolean(false);
          if (stroke instanceof BasicStroke) {
              final BasicStroke s = (BasicStroke) stroke;
              stream.writeObject(BasicStroke.class);
              stream.writeFloat(s.getLineWidth());
              stream.writeInt(s.getEndCap());
              stream.writeInt(s.getLineJoin());
              stream.writeFloat(s.getMiterLimit());
              stream.writeObject(s.getDashArray());
              stream.writeFloat(s.getDashPhase());
          }
          else {
              stream.writeObject(stroke.getClass());
              stream.writeObject(stroke);
          }
      }
      else {
          stream.writeBoolean(true);
      }
  }
}



Smokey effect

     
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Overlap extends JPanel {
  public static void main(String[] args) {
    JFrame f = new JFrame();
    f.getContentPane().add(new Overlap());
    f.setSize(300, 200);
    f.setVisible(true);
  }
  public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    double x = 15, y = 50, w = 70, h = 70;
    Ellipse2D e = new Ellipse2D.Double(x, y, w, h);
    g2.setStroke(new BasicStroke(8));
    Color smokeyColor = new Color(128, 128, 128, 128);
    g2.setPaint(smokeyColor);
    g2.fill(e);
    g2.draw(e);
    e.setFrame(x + 100, y, w, h);
    g2.setPaint(Color.black);
    g2.draw(e);
    g2.setPaint(Color.gray);
    g2.fill(e);
    e.setFrame(x + 200, y, w, h);
    g2.setPaint(Color.gray);
    g2.fill(e);
    g2.setPaint(Color.black);
    g2.draw(e);
  }
}



Stroke with iron effect

     
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class PaintingAndStroking extends JPanel{
  public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    double x = 15, y = 50, w = 70, h = 70;
    Ellipse2D e = new Ellipse2D.Double(x, y, w, h);
    GradientPaint gp = new GradientPaint(75, 75, Color.white, 95, 95,
        Color.gray, true);
    // Fill with a gradient.
    g2.setPaint(gp);
    g2.fill(e);
    // Stroke with a solid color.
    e.setFrame(x + 100, y, w, h);
    g2.setPaint(Color.black);
    g2.setStroke(new BasicStroke(8));
    g2.draw(e);
    // Stroke with a gradient.
    e.setFrame(x + 200, y, w, h);
    g2.setPaint(gp);
    g2.draw(e);
  }
  public static void main(String[] args) {
    JFrame f = new JFrame();
    f.getContentPane().add(new PaintingAndStroking());
    f.setSize(350, 250);
    f.show();
  }
}



Stroking or Filling with a Texture

     
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.TexturePaint;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class BasicDraw {
  public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.add(new MyComponent());
    frame.setSize(300, 300);
    frame.setVisible(true);
  }
}
class MyComponent extends JComponent {
  public void paint(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;
    int x = 10;
    int y = 10;
    int width = 50;
    int height = 25;
    BufferedImage bi = new BufferedImage(20,20,BufferedImage.TYPE_INT_RGB);
    
    TexturePaint texture = new TexturePaint(bi, new Rectangle(x, y, width, height));
    g2d.setPaint(texture);
  }
}



Thick stroke demo

     
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ThickStrokeDemo extends JPanel {
  public void init() {
    setBackground(Color.white);
  }
  public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    g2.setStroke(new BasicStroke(8.0f));
    g2.setPaint(Color.blue);
    
    Rectangle r = new Rectangle(5,5,200,200);
    
    g2.draw(r);
  }
  public static void main(String s[]) {
    JFrame f = new JFrame();
    f.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    ThickStrokeDemo p = new ThickStrokeDemo();
    f.getContentPane().add("Center", p);
    p.init();
    f.pack();
    f.setSize(new Dimension(250, 250));
    f.show();
  }
}



Tries to deduct the stroke-type from the given stroke object.

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



Tries to extract the stroke-width from the given stroke object.

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