edu.uci.ics.jung.visualization.util.VertexShapeFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jung-visualization Show documentation
Show all versions of jung-visualization Show documentation
Core visualization support for the JUNG project
The newest version!
/*
* Copyright (c) 2003, The JUNG Authors
* All rights reserved.
*
* This software is open-source under the BSD license; see either "license.txt"
* or https://github.com/jrtom/jung/blob/master/LICENSE for a description.
*
* Created on Jul 20, 2004
*/
package edu.uci.ics.jung.visualization.util;
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;
import java.awt.geom.RoundRectangle2D;
import com.google.common.base.Function;
import com.google.common.base.Functions;
/**
* A utility class for generating Shape
s for drawing vertices.
* The available shapes include rectangles, rounded rectangles, ellipses,
* regular polygons, and regular stars. The dimensions of the requested
* shapes are defined by the specified vertex size function (specified by
* a {@code Function super V, Integer>}) and vertex aspect ratio function
* (specified by a {@code Function super V, Float>}) implementations: the width
* of the bounding box of the shape is given by the vertex size, and the
* height is given by the size multiplied by the vertex's aspect ratio.
*
* @author Joshua O'Madadhain
*/
public class VertexShapeFactory
{
protected Function super V, Integer> vsf;
protected Function super V, Float> varf;
/**
* Creates an instance with the specified vertex size and aspect ratio functions.
*
* @param vsf provides a size (width) for each vertex
* @param varf provides a height/width ratio for each vertex
*/
public VertexShapeFactory(Function super V,Integer> vsf, Function super V,Float> varf)
{
this.vsf = vsf;
this.varf = varf;
}
/**
* Creates a VertexShapeFactory
with a constant size of
* 10 and a constant aspect ratio of 1.
*/
public VertexShapeFactory()
{
this(Functions.constant(10),
Functions.constant(1.0f));
}
private static final Rectangle2D theRectangle = new Rectangle2D.Float();
/**
* Returns a Rectangle2D
whose width and
* height are defined by this instance's size and
* aspect ratio functions for this vertex.
*
* @param v the vertex for which the shape will be drawn
* @return a rectangle for this vertex
*/
public Rectangle2D getRectangle(V v)
{
float width = vsf.apply(v);
float height = width * varf.apply(v);
float h_offset = -(width / 2);
float v_offset = -(height / 2);
theRectangle.setFrame(h_offset, v_offset, width, height);
return theRectangle;
}
private static final Ellipse2D theEllipse = new Ellipse2D.Float();
/**
* Returns a Ellipse2D
whose width and
* height are defined by this instance's size and
* aspect ratio functions for this vertex.
*
* @param v the vertex for which the shape will be drawn
* @return an ellipse for this vertex
*/
public Ellipse2D getEllipse(V v)
{
theEllipse.setFrame(getRectangle(v));
return theEllipse;
}
private static final RoundRectangle2D theRoundRectangle =
new RoundRectangle2D.Float();
/**
* Returns a RoundRectangle2D
whose width and
* height are defined by this instance's size and
* aspect ratio functions for this vertex. The arc size is
* set to be half the minimum of the height and width of the frame.
*
* @param v the vertex for which the shape will be drawn
* @return an round rectangle for this vertex
*/
public RoundRectangle2D getRoundRectangle(V v)
{
Rectangle2D frame = getRectangle(v);
float arc_size = (float)Math.min(frame.getHeight(), frame.getWidth()) / 2;
theRoundRectangle.setRoundRect(frame.getX(), frame.getY(),
frame.getWidth(), frame.getHeight(), arc_size, arc_size);
return theRoundRectangle;
}
private static final GeneralPath thePolygon = new GeneralPath();
/**
* Returns a regular num_sides
-sided
* Polygon
whose bounding
* box's width and height are defined by this instance's size and
* aspect ratio functions for this vertex.
*
* @param v the vertex for which the shape will be drawn
* @param num_sides the number of sides of the polygon; must be ≥ 3.
* @return a regular polygon for this vertex
*/
public Shape getRegularPolygon(V v, int num_sides)
{
if (num_sides < 3)
throw new IllegalArgumentException("Number of sides must be >= 3");
Rectangle2D frame = getRectangle(v);
float width = (float)frame.getWidth();
float height = (float)frame.getHeight();
// generate coordinates
double angle = 0;
thePolygon.reset();
thePolygon.moveTo(0,0);
thePolygon.lineTo(width, 0);
double theta = (2 * Math.PI) / num_sides;
for (int i = 2; i < num_sides; i++)
{
angle -= theta;
float delta_x = (float) (width * Math.cos(angle));
float delta_y = (float) (width * Math.sin(angle));
Point2D prev = thePolygon.getCurrentPoint();
thePolygon.lineTo((float)prev.getX() + delta_x, (float)prev.getY() + delta_y);
}
thePolygon.closePath();
// scale polygon to be right size, translate to center at (0,0)
Rectangle2D r = thePolygon.getBounds2D();
double scale_x = width / r.getWidth();
double scale_y = height / r.getHeight();
float translationX = (float) (r.getMinX() + r.getWidth()/2);
float translationY = (float) (r.getMinY() + r.getHeight()/2);
AffineTransform at = AffineTransform.getScaleInstance(scale_x, scale_y);
at.translate(-translationX, -translationY);
Shape shape = at.createTransformedShape(thePolygon);
return shape;
}
/**
* Returns a regular Polygon
of num_points
* points whose bounding
* box's width and height are defined by this instance's size and
* aspect ratio functions for this vertex.
*
* @param v the vertex for which the shape will be drawn
* @param num_points the number of points of the polygon; must be ≥ 5.
* @return an star shape for this vertex
*/
public Shape getRegularStar(V v, int num_points)
{
if (num_points < 5)
throw new IllegalArgumentException("Number of sides must be >= 5");
Rectangle2D frame = getRectangle(v);
float width = (float) frame.getWidth();
float height = (float) frame.getHeight();
// generate coordinates
double theta = (2 * Math.PI) / num_points;
double angle = -theta/2;
thePolygon.reset();
thePolygon.moveTo(0,0);
float delta_x = width * (float)Math.cos(angle);
float delta_y = width * (float)Math.sin(angle);
Point2D prev = thePolygon.getCurrentPoint();
thePolygon.lineTo((float)prev.getX() + delta_x, (float)prev.getY() + delta_y);
for (int i = 1; i < num_points; i++)
{
angle += theta;
delta_x = width * (float)Math.cos(angle);
delta_y = width * (float)Math.sin(angle);
prev = thePolygon.getCurrentPoint();
thePolygon.lineTo((float)prev.getX() + delta_x, (float)prev.getY() + delta_y);
angle -= theta*2;
delta_x = width * (float)Math.cos(angle);
delta_y = width * (float)Math.sin(angle);
prev = thePolygon.getCurrentPoint();
thePolygon.lineTo((float)prev.getX() + delta_x, (float)prev.getY() + delta_y);
}
thePolygon.closePath();
// scale polygon to be right size, translate to center at (0,0)
Rectangle2D r = thePolygon.getBounds2D();
double scale_x = width / r.getWidth();
double scale_y = height / r.getHeight();
float translationX = (float) (r.getMinX() + r.getWidth()/2);
float translationY = (float) (r.getMinY() + r.getHeight()/2);
AffineTransform at = AffineTransform.getScaleInstance(scale_x, scale_y);
at.translate(-translationX, -translationY);
Shape shape = at.createTransformedShape(thePolygon);
return shape;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy