package com.horstmann.violet.product.diagram.abstracts.edge.bentstyle;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Arrays;
/**
* A style for a segmented line that indicates the number and sequence of bends.
*
* @author Adrian Bobrowski <adrian071993@gmail.com>
* @date 20.02.2016
*/
public class BentStyle
{
/**
* Default constructor
*/
private BentStyle()
{
}
/**
* Gets the four connecting points at which a bent line connects to a rectangle.
*/
private Point2D[] connectionPoints(Rectangle2D r)
{
Point2D[] a = new Point2D[4];
a[0] = new Point2D.Double(r.getX(), r.getCenterY());
a[1] = new Point2D.Double(r.getMaxX(), r.getCenterY());
a[2] = new Point2D.Double(r.getCenterX(), r.getY());
a[3] = new Point2D.Double(r.getCenterX(), r.getMaxY());
return a;
}
/**
* Gets the points at which a line joining two rectangles is bent according to a bent style.
*
* @param connectionPoints the points to use (starting point, optional middle points and ending points merged in an array of
* points)
* @return an array list of points at which to bend the segmented line joining the two rectangles
*/
public ArrayList<Point2D> getPath(Point2D... connectionPoints)
{
if (connectionPoints.length < 2)
{
throw new RuntimeException("BentStyleChoiceList need at least two points to process the path of an edge");
}
Point2D startingPoint = connectionPoints[0];
Point2D endingPoint = connectionPoints[connectionPoints.length - 1];
ArrayList<Point2D> r = null;
// Try to get current path
if (this == STRAIGHT) r = getStraightPath(startingPoint, endingPoint);
else if (this == FREE) r = getFreePath(connectionPoints);
else if (this == HV) r = getHVPath(startingPoint, endingPoint);
else if (this == VH) r = getVHPath(startingPoint, endingPoint);
else if (this == HVH) r = getHVHPath(startingPoint, endingPoint);
else if (this == VHV) r = getVHVPath(startingPoint, endingPoint);
if (r != null) return r;
// Try to inverse path
if (startingPoint.equals(endingPoint)) r = getSelfPath(startingPoint);
else if (this == HVH) r = getVHVPath(startingPoint, endingPoint);
else if (this == VHV) r = getHVHPath(startingPoint, endingPoint);
else if (this == HV) r = getVHPath(startingPoint, endingPoint);
else if (this == VH) r = getHVPath(startingPoint, endingPoint);
else if (this == FREE) r = getFreePath(connectionPoints);
if (r != null) return r;
// Return default path
return getStraightPath(startingPoint, endingPoint);
}
/**
* Gets an Vertical-Horizontal-Vertival path
*
* @param startingRectangle
* @param endingRectangle
* @return an array list of points
*/
private ArrayList<Point2D> getVHVPath(Point2D startingPoint, Point2D endingPoint)
{
ArrayList<Point2D> r = new ArrayList<Point2D>();
double x1 = startingPoint.getX();
double x2 = endingPoint.getX();
double y1;
double y2;
if (startingPoint.getY() + 2 * MIN_SEGMENT <= endingPoint.getY())
{
y1 = startingPoint.getY();
y2 = endingPoint.getY();
}
else if (endingPoint.getY() + 2 * MIN_SEGMENT <= startingPoint.getY())
{
y1 = startingPoint.getY();
y2 = endingPoint.getY();
}
else return null;
if (Math.abs(x1 - x2) <= MIN_SEGMENT)
{
r.add(new Point2D.Double(x2, y1));
r.add(new Point2D.Double(x2, y2));
}
else
{
r.add(new Point2D.Double(x1, y1));
r.add(new Point2D.Double(x1, (y1 + y2) / 2));
r.add(new Point2D.Double(x2, (y1 + y2) / 2));
r.add(new Point2D.Double(x2, y2));
}
return r;
}
/**
* Gets an Horizontal-Vertical-Horizontal path
*
* @param startingRectangle
* @param endingRectangle
* @return an array list of points
*/
private ArrayList<Point2D> getHVHPath(Point2D startingPoint, Point2D endingPoint)
{
ArrayList<Point2D> r = new ArrayList<Point2D>();
double x1;
double x2;
double y1 = startingPoint.getY();
double y2 = endingPoint.getY();
if (startingPoint.getX() + 2 * MIN_SEGMENT <= endingPoint.getX())
{
x1 = startingPoint.getX();
x2 = endingPoint.getX();
}
else if (endingPoint.getX() + 2 * MIN_SEGMENT <= startingPoint.getX())
{
x1 = startingPoint.getX();
x2 = endingPoint.getX();
}
else return null;
if (Math.abs(y1 - y2) <= MIN_SEGMENT)
{
r.add(new Point2D.Double(x1, y2));
r.add(new Point2D.Double(x2, y2));
}
else
{
r.add(new Point2D.Double(x1, y1));
r.add(new Point2D.Double((x1 + x2) / 2, y1));
r.add(new Point2D.Double((x1 + x2) / 2, y2));
r.add(new Point2D.Double(x2, y2));
}
return r;
}
/**
* Gets a Vertical-Horizontal path
*
* @param startingRectangle
* @param endingRectangle
* @return an array list of points
*/
private ArrayList<Point2D> getVHPath(Point2D startingPoint, Point2D endingPoint)
{
ArrayList<Point2D> r = new ArrayList<Point2D>();
double x1 = startingPoint.getX();
double x2;
double y1;
double y2 = endingPoint.getY();
if (x1 + MIN_SEGMENT <= endingPoint.getX() || x1 - MIN_SEGMENT >= endingPoint.getX())
{
x2 = endingPoint.getX();
}
else
{
return null;
}
if (y2 + MIN_SEGMENT <= startingPoint.getY() || y2 - MIN_SEGMENT >= startingPoint.getY())
{
y1 = startingPoint.getY();
}
else
{
return null;
}
r.add(new Point2D.Double(x1, y1));
r.add(new Point2D.Double(x1, y2));
r.add(new Point2D.Double(x2, y2));
return r;
}
/**
* Gets an Horizontal-Vertical path
*
* @param startingRectangle
* @param endingRectangle
* @return an array list of points
*/
private ArrayList<Point2D> getHVPath(Point2D startingPoint, Point2D endingPoint)
{
ArrayList<Point2D> r = new ArrayList<Point2D>();
double x1;
double x2 = endingPoint.getX();
double y1 = startingPoint.getY();
double y2;
if (x2 + MIN_SEGMENT <= startingPoint.getX()) x1 = startingPoint.getX();
else if (x2 - MIN_SEGMENT >= startingPoint.getX()) x1 = startingPoint.getX();
else return null;
if (y1 + MIN_SEGMENT <= endingPoint.getY()) y2 = endingPoint.getY();
else if (y1 - MIN_SEGMENT >= endingPoint.getY()) y2 = endingPoint.getY();
else return null;
r.add(new Point2D.Double(x1, y1));
r.add(new Point2D.Double(x2, y1));
r.add(new Point2D.Double(x2, y2));
return r;
}
/**
* Gets a straight path
*
* @param startingRectangle
* @param endingRectangle
* @return an array list of points
*/
private ArrayList<Point2D> getStraightPath(Point2D startingPoint, Point2D endingPoint)
{
ArrayList<Point2D> r = new ArrayList<Point2D>();
r.add(startingPoint);
r.add(endingPoint);
return r;
}
/**
* Gets a free path
*
* @param connectionPoints
* @return
*/
private ArrayList<Point2D> getFreePath(Point2D... connectionPoints)
{
ArrayList<Point2D> r = new ArrayList<Point2D>();
r.addAll(Arrays.asList(connectionPoints));
return r;
}
/**
* Gets the points at which a line joining two rectangles is bent according to a bent style.
*
* @param s the starting and ending rectangle
*/
private ArrayList<Point2D> getSelfPath(Point2D p)
{
ArrayList<Point2D> r = new ArrayList<Point2D>();
double x1 = p.getX() + SELF_WIDTH * 3 / 4;
double y1 = p.getY();
double y2 = p.getY() - SELF_HEIGHT;
double x2 = p.getX() + 2 * SELF_WIDTH;
double y3 = p.getY() + SELF_HEIGHT / 4;
double x3 = p.getX() + SELF_WIDTH;
r.add(new Point2D.Double(x1, y1));
r.add(new Point2D.Double(x1, y2));
r.add(new Point2D.Double(x2, y2));
r.add(new Point2D.Double(x2, y3));
r.add(new Point2D.Double(x3, y3));
return r;
}
/** minimum segment size */
private static final int MIN_SEGMENT = 15;
/** width on self path */
private static final int SELF_WIDTH = 30;
/** height on self path */
private static final int SELF_HEIGHT = 25;
/** straight bent style */
public static final BentStyle STRAIGHT = new BentStyle();
/** free bent style */
public static final BentStyle FREE = new BentStyle();
/** Horizontal-Vertical bent style */
public static final BentStyle HV = new BentStyle();
/** Vertical-Horizontal bent style */
public static final BentStyle VH = new BentStyle();
/** Horizontal-Vertical-Horizontal bent style */
public static final BentStyle HVH = new BentStyle();
/** Vertical-Horizontal-Vertical bent style */
public static final BentStyle VHV = new BentStyle();
/** Automatic bent style */
public static final BentStyle AUTO = new BentStyle();
}