001/*
002 * $Id: ShapeUtils.java 4082 2011-11-15 18:39:43Z kschaefe $
003 *
004 * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle,
005 * Santa Clara, California 95054, U.S.A. All rights reserved.
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 * 
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015 * Lesser General Public License for more details.
016 * 
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020 */
021package org.jdesktop.swingx.util;
022
023import java.awt.Font;
024import java.awt.Graphics;
025import java.awt.Graphics2D;
026import java.awt.Polygon;
027import java.awt.Shape;
028import java.awt.font.GlyphVector;
029import java.awt.geom.AffineTransform;
030import java.awt.geom.Area;
031import java.awt.geom.Ellipse2D;
032import java.awt.geom.GeneralPath;
033import java.awt.geom.Point2D;
034import java.awt.geom.Rectangle2D;
035import java.awt.image.BufferedImage;
036
037/**
038 * 
039 * @author joshy
040 */
041public final class ShapeUtils {
042
043    /** Creates a new instance of ShapeUtils */
044    private ShapeUtils() {
045    }
046
047    public static Shape generatePolygon(int sides, int outsideRadius, boolean normalize) {
048        return generatePolygon(sides, outsideRadius, 0, normalize);
049    }
050
051    public static Shape generatePolygon(int sides, int outsideRadius, int insideRadius,
052            boolean normalize) {
053        Shape shape = generatePolygon(sides, outsideRadius, insideRadius);
054        if (normalize) {
055            Rectangle2D bounds = shape.getBounds2D();
056            GeneralPath path = new GeneralPath(shape);
057            shape = path.createTransformedShape(AffineTransform.getTranslateInstance(
058                    -bounds.getX(), -bounds.getY()));
059        }
060        return shape;
061    }
062
063    public static Shape generatePolygon(int sides, int outsideRadius, int insideRadius) {
064        if (sides < 3) {
065            return new Ellipse2D.Float(0, 0, 10, 10);
066        }
067
068        AffineTransform trans = new AffineTransform();
069        Polygon poly = new Polygon();
070        for (int i = 0; i < sides; i++) {
071            trans.rotate(Math.PI * 2 / sides / 2);
072            Point2D out = trans.transform(new Point2D.Float(0, outsideRadius), null);
073            poly.addPoint((int) out.getX(), (int) out.getY());
074            trans.rotate(Math.PI * 2 / sides / 2);
075            if (insideRadius > 0) {
076                Point2D in = trans.transform(new Point2D.Float(0, insideRadius), null);
077                poly.addPoint((int) in.getX(), (int) in.getY());
078            }
079        }
080
081        return poly;
082    }
083
084    public static Shape generateShapeFromText(Font font, char ch) {
085        return generateShapeFromText(font, String.valueOf(ch));
086    }
087
088    public static Shape generateShapeFromText(Font font, String string) {
089        BufferedImage img = GraphicsUtilities.createCompatibleTranslucentImage(1, 1);
090        Graphics2D g2 = img.createGraphics();
091
092        try {
093            GlyphVector vect = font.createGlyphVector(g2.getFontRenderContext(), string);
094            Shape shape = vect.getOutline(0f, (float) -vect.getVisualBounds().getY());
095
096            return shape;
097        } finally {
098            g2.dispose();
099        }
100    }
101
102    /**
103     * Sets the clip on a graphics object by merging a supplied clip with the existing one. The new
104     * clip will be an intersection of the old clip and the supplied clip. The old clip shape will
105     * be returned. This is useful for resetting the old clip after an operation is performed.
106     * 
107     * @param g
108     *            the graphics object to update
109     * @param clip
110     *            a new clipping region to add to the graphics clip.
111     * @return the current clipping region of the supplied graphics object. This may return
112     *         {@code null} if the current clip is {@code null}.
113     * @throws NullPointerException
114     *             if any parameter is {@code null}
115     */
116    public static Shape mergeClip(Graphics g, Shape clip) {
117        Shape oldClip = g.getClip();
118        if (oldClip == null) {
119            g.setClip(clip);
120            return null;
121        }
122        Area area = new Area(oldClip);
123        area.intersect(new Area(clip));// new Rectangle(0,0,width,height)));
124        g.setClip(area);
125        return oldClip;
126    }
127}