    001: import java.awt.geom.Point2D;
    002: import java.awt.geom.Rectangle2D;
    003: import java.util.ArrayList;
    004:
    005: /**
    006:    A style for a segmented line that indicates the number
    007:    and sequence of bends.
    008: */
    009: public class BentStyle extends SerializableEnumeration
    010: {
    011:    private BentStyle() {}
    012:
    013:    /**
    014:       Gets the points at which a line joining two rectangles
    015:       is bent according to this bent style.
    016:       @param start the starting rectangle
    017:       @param end the ending rectangle
    018:       @return an array list of points at which to bend the
    019:       segmented line joining the two rectangles
    020:    */
    021:    public ArrayList getPath(Rectangle2D start, Rectangle2D end)
    022:    {
    023:       ArrayList r = getPath(this, start, end);
    024:       if (r != null) return r;
    025:
    026:       if (this == HVH) r = getPath(VHV, start, end);
    027:       else if (this == VHV) r = getPath(HVH, start, end);
    028:       else if (this == HV) r = getPath(VH, start, end);
    029:       else if (this == VH) r = getPath(HV, start, end);
    030:       if (r != null) return r;
    031:
    032:       return getPath(STRAIGHT, start, end);
    033:    }
    034:
    035:    /**
    036:       Gets the four connecting points at which a bent line
    037:       connects to a rectangle.
    038:    */
    039:    private static Point2D[] connectionPoints(Rectangle2D r)
    040:    {
    041:       Point2D[] a = new Point2D[4];
    042:       a[0] = new Point2D.Double(r.getX(), r.getCenterY());
    043:       a[1] = new Point2D.Double(r.getMaxX(), r.getCenterY());
    044:       a[2] = new Point2D.Double(r.getCenterX(), r.getY());
    045:       a[3] = new Point2D.Double(r.getCenterX(), r.getMaxY());
    046:       return a;
    047:    }
    048:
    049:    /**
    050:       Gets the points at which a line joining two rectangles
    051:       is bent according to a bent style.
    052:       @param start the starting rectangle
    053:       @param end the ending rectangle
    054:       @return an array list of points at which to bend the
    055:       segmented line joining the two rectangles
    056:    */
    057:    private static ArrayList getPath(BentStyle bent,
    058:       Rectangle2D s, Rectangle2D e)
    059:    {
    060:       ArrayList r = new ArrayList();
    061:       if (bent == STRAIGHT)
    062:       {
    063:          Point2D[] a = connectionPoints(s);
    064:          Point2D[] b = connectionPoints(e);
    065:          Point2D p = a[0];
    066:          Point2D q = b[0];
    067:          double distance = p.distance(q);
    068:          for (int i = 0; i < a.length; i++)
    069:             for (int j = 0; j < b.length; j++)
    070:             {
    071:                double d = a[i].distance(b[j]);
    072:                if (d < distance)
    073:                {
    074:                   p = a[i]; q = b[j];
    075:                   distance = d;
    076:                }
    077:             }
    078:          r.add(p);
    079:          r.add(q);
    080:       }
    081:       else if (bent == HV)
    082:       {
    083:          double x1;
    084:          double x2 = e.getCenterX();
    085:          double y1 = s.getCenterY();
    086:          double y2;
    087:          if (x2 + MIN_SEGMENT <= s.getX())
    088:             x1 = s.getX();
    089:          else if (x2 - MIN_SEGMENT >= s.getMaxX())
    090:             x1 = s.getMaxX();
    091:          else return null;
    092:          if (y1 + MIN_SEGMENT <= e.getY())
    093:             y2 = e.getY();
    094:          else if (y1 - MIN_SEGMENT >= e.getMaxY())
    095:             y2 = e.getMaxY();
    096:          else return null;
    097:          r.add(new Point2D.Double(x1, y1));
    098:          r.add(new Point2D.Double(x2, y1));
    099:          r.add(new Point2D.Double(x2, y2));
    100:       }
    101:       else if (bent == VH)
    102:       {
    103:          double x1 = s.getCenterX();
    104:          double x2;
    105:          double y1;
    106:          double y2 = e.getCenterY();
    107:          if (x1 + MIN_SEGMENT <= e.getX())
    108:             x2 = e.getX();
    109:          else if (x1 - MIN_SEGMENT >= e.getMaxX())
    110:             x2 = e.getMaxX();
    111:          else return null;
    112:          if (y2 + MIN_SEGMENT <= s.getY())
    113:             y1 = s.getY();
    114:          else if (y2 - MIN_SEGMENT >= s.getMaxY())
    115:             y1 = s.getMaxY();
    116:          else return null;
    117:          r.add(new Point2D.Double(x1, y1));
    118:          r.add(new Point2D.Double(x1, y2));
    119:          r.add(new Point2D.Double(x2, y2));
    120:       }
    121:       else if (bent == HVH)
    122:       {
    123:          double x1;
    124:          double x2;
    125:          double y1 = s.getCenterY();
    126:          double y2 = e.getCenterY();
    127:          if (s.getMaxX() + 2 * MIN_SEGMENT <= e.getX())
    128:          {
    129:             x1 = s.getMaxX();
    130:             x2 = e.getX();
    131:          }
    132:          else if (e.getMaxX() + 2 * MIN_SEGMENT <= s.getX())
    133:          {
    134:             x1 = s.getX();
    135:             x2 = e.getMaxX();
    136:          }
    137:          else return null;
    138:          if (Math.abs(y1 - y2) <= MIN_SEGMENT)
    139:          {
    140:             r.add(new Point2D.Double(x1, (y1 + y2) / 2));
    141:             r.add(new Point2D.Double(x2, (y1 + y2) / 2));
    142:          }
    143:          else
    144:          {
    145:             r.add(new Point2D.Double(x1, y1));
    146:             r.add(new Point2D.Double((x1 + x2) / 2, y1));
    147:             r.add(new Point2D.Double((x1 + x2) / 2, y2));
    148:             r.add(new Point2D.Double(x2, y2));
    149:          }
    150:       }
    151:       else if (bent == VHV)
    152:       {
    153:          double x1 = s.getCenterX();
    154:          double x2 = e.getCenterX();
    155:          double y1;
    156:          double y2;
    157:          if (s.getMaxY() + 2 * MIN_SEGMENT <= e.getY())
    158:          {
    159:             y1 = s.getMaxY();
    160:             y2 = e.getY();
    161:          }
    162:          else if (e.getMaxY() + 2 * MIN_SEGMENT <= s.getY())
    163:          {
    164:             y1 = s.getY();
    165:             y2 = e.getMaxY();
    166:
    167:          }
    168:          else return null;
    169:          if (Math.abs(x1 - x2) <= MIN_SEGMENT)
    170:          {
    171:             r.add(new Point2D.Double((x1 + x2) / 2, y1));
    172:             r.add(new Point2D.Double((x1 + x2) / 2, y2));
    173:          }
    174:          else
    175:          {
    176:             r.add(new Point2D.Double(x1, y1));
    177:             r.add(new Point2D.Double(x1, (y1 + y2) / 2));
    178:             r.add(new Point2D.Double(x2, (y1 + y2) / 2));
    179:             r.add(new Point2D.Double(x2, y2));
    180:          }
    181:       }
    182:       else return null;
    183:       return r;
    184:    }
    185:
    186:    private static final int MIN_SEGMENT = 10;
    187:
    188:    public static final BentStyle STRAIGHT = new BentStyle();
    189:    public static final BentStyle HV = new BentStyle();
    190:    public static final BentStyle VH = new BentStyle();
    191:    public static final BentStyle HVH = new BentStyle();
    192:    public static final BentStyle VHV = new BentStyle();
    193: }