All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.uci.ics.jung.visualization.FourPassImageShaper Maven / Gradle / Ivy

/*
 * Copyright (c) 2005, the JUNG Project and the Regents of the University of
 * California All rights reserved.
 *
 * This software is open-source under the BSD license; see either "license.txt"
 * or http://jung.sourceforge.net/license.txt for a description.
 *
 * Created on Jun 17, 2005
 */

package edu.uci.ics.jung.visualization;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.imageio.ImageIO;

/**
 * Provides factory methods that, given a BufferedImage, an Image,
 * or the fileName of an image, will return a java.awt.Shape that
 * is the contiguous traced outline of the opaque part of the image.
 * This could be used to define an image for use in a Vertex, where
 * the shape used for picking and edge-arrow placement follows the
 * opaque part of an image that has a transparent background.
 * The methods try to detect lines in order to minimize points
 * in the path
 * 
 * @author Tom Nelson
 *
 * 
 */
public class FourPassImageShaper {
    
    /**
     * given the fileName of an image, possibly with a transparent
     * background, return the Shape of the opaque part of the image
     * @param fileName name of the image, loaded from the classpath
     * @return the Shape
     */
    public static Shape getShape(String fileName) {
        return getShape(fileName, Integer.MAX_VALUE);
    }
    public static Shape getShape(String fileName, int max) {
        BufferedImage image = null;
        try {
            image = ImageIO.read(FourPassImageShaper.class.getResource(fileName));
        } catch(IOException ex) {
            ex.printStackTrace();
        }
        return getShape(image, max);
    }
    
    /**
     * Given an image, possibly with a transparent background, return
     * the Shape of the opaque part of the image
     * @param image
     * @return the Shape
     */
    public static Shape getShape(Image image) {
        return getShape(image, Integer.MAX_VALUE);
    }
    public static Shape getShape(Image image, int max) {
        BufferedImage bi = 
            new BufferedImage(image.getWidth(null), image.getHeight(null), 
                    BufferedImage.TYPE_INT_ARGB);
        Graphics g = bi.createGraphics();
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return getShape(bi, max);
    }
    
    /**
     * Given an image, possibly with a transparent background, return
     * the Shape of the opaque part of the image
     * 
     * If the image is larger than max in either direction, scale the
     * image down to max-by-max, do the trace (on fewer points) then
     * scale the resulting shape back up to the size of the original
     * image.
     * 
     * @param image the image to trace
     * @param max used to restrict number of points in the resulting shape
     * @return the Shape
     */
    public static Shape getShape(BufferedImage image, int max) {
        
        float width = image.getWidth();
        float height = image.getHeight();
        if(width > max || height > max) {
            BufferedImage smaller = 
                new BufferedImage(max, max, BufferedImage.TYPE_INT_ARGB);
            Graphics g = smaller.createGraphics();
            AffineTransform at = AffineTransform.getScaleInstance(max/width,max/height);
            AffineTransform back = AffineTransform.getScaleInstance(width/max,height/max);
            Graphics2D g2 = (Graphics2D)g;
            g2.drawImage(image, at, null);
            g2.dispose();
            return back.createTransformedShape(getShape(smaller));
        } else {
            return getShape(image);
        }
    }
    
    public static Shape getShape(BufferedImage image) {
        Area area = new Area(leftEdge(image));
        area.intersect(new Area(bottomEdge(image)));
        area.intersect(new Area(rightEdge(image)));
        area.intersect(new Area(topEdge(image)));
        return area;
    }
    /**
     * Checks to see if point p is on a line that passes thru
     * points p1 and p2. If p is on the line, extend the line
     * segment so that it is from p1 to the location of p.
     * If the point p is not on the line, update my shape
     * with a line extending to the old p2 location, make
     * the old p2 the new p1, and make p2 the old p
     * @param p1
     * @param p2
     * @param p
     * @param line
     * @param path
     * @return
     */
    private static Point2D detectLine(Point2D p1, Point2D p2, Point2D p, 
            Line2D line, GeneralPath path) {
        if(p2 == null) {
            p2 = p;
            line.setLine(p1,p2);
        }
        // check for line
        else if(line.ptLineDistSq(p) < 1) { // its on the line
            // make it p2
            p2.setLocation(p);
        } else { // its not on the current line
            p1.setLocation(p2);
            p2.setLocation(p);
            line.setLine(p1,p2);
            path.lineTo((float)p1.getX(), (float)p1.getY());
        }
        return p2;
    }
    /**
     * trace the left side of the image
     * @param image
     * @param path
     * @return
     */
    private static Shape leftEdge(BufferedImage image) {
        GeneralPath path = new GeneralPath();
        Point2D p1 = new Point2D.Float(image.getWidth()-1, 0);
        Point2D p2 = null;
        Line2D line = new Line2D.Float();
        Point2D p = new Point2D.Float();
        path.moveTo(image.getWidth()-1, 0);
        
        for(int i=0; i=0; j--) {
                if((image.getRGB(i,j) & 0xff000000) != 0) {
                    // this is a point I want
                    p.setLocation(i,j);
                    break;
                }
            }
            p2 = detectLine(p1, p2, p, line, path);
        }
        p.setLocation(image.getWidth()-1, 0);
        detectLine(p1, p2, p, line, path);
        path.closePath();
        return path;
    }
    
    /**
     * trace the right side of the image
     * @param image
     * @param path
     * @param start
     * @return
     */
    private static Shape rightEdge(BufferedImage image) {
        GeneralPath path = new GeneralPath();
        Point2D p1 = new Point2D.Float(0, image.getHeight()-1);
        Point2D p2 = null;
        Line2D line = new Line2D.Float();
        Point2D p = new Point2D.Float();
        path.moveTo(0, image.getHeight()-1);
        
        for(int i=image.getHeight()-1; i>=0; i--) {
            p.setLocation(0, i);
            for(int j=image.getWidth()-1; j>=0; j--) {
                if((image.getRGB(j,i) & 0xff000000) != 0) {
                    // this is a point I want
                    p.setLocation(j,i);
                    break;
                }
            }
            p2 = detectLine(p1, p2, p, line, path);
        }
        p.setLocation(0, 0);
        detectLine(p1, p2, p,line, path);
        path.closePath();
        return path;
    }
    
    /**
     * trace the top of the image
     * @param image
     * @param path
     * @param start
     * @return
     */
    private static Shape topEdge(BufferedImage image) {
        GeneralPath path = new GeneralPath();
        Point2D p1 = new Point2D.Float(image.getWidth()-1, image.getHeight()-1);
        Point2D p2 = null;
        Line2D line = new Line2D.Float();
        Point2D p = new Point2D.Float();
        path.moveTo(image.getWidth()-1, image.getHeight()-1);
        
        for(int i=image.getWidth()-1; i>=0; i--) {
            p.setLocation(i, image.getHeight()-1);
            for(int j=0; j




© 2015 - 2024 Weber Informatics LLC | Privacy Policy