    001: import java.awt.Graphics2D;
    002: import java.awt.geom.Point2D;
    003: import java.awt.geom.Rectangle2D;
    004: import java.awt.geom.RectangularShape;
    005: import java.io.IOException;
    006: import java.io.ObjectInputStream;
    007: import java.io.ObjectOutputStream;
    008:
    009: /**
    010:    A node that has a rectangular shape.
    011: */
    012: public abstract class RectangularNode implements Node
    013: {
    014:    public Object clone()
    015:    {
    016:       try
    017:       {
    018:          RectangularNode cloned = (RectangularNode) super.clone();
    019:          cloned.bounds = (Rectangle2D) bounds.clone();
    020:          return cloned;
    021:       }
    022:       catch (CloneNotSupportedException exception)
    023:       {
    024:          return null;
    025:       }
    026:    }
    027:
    028:    public void translate(double dx, double dy)
    029:    {
    030:       bounds.setFrame(bounds.getX() + dx,
    031:          bounds.getY() + dy,
    032:          bounds.getWidth(),
    033:          bounds.getHeight());
    034:    }
    035:
    036:    public boolean contains(Point2D p)
    037:    {
    038:       return bounds.contains(p);
    039:    }
    040:
    041:    public Rectangle2D getBounds()
    042:    {
    043:       return (Rectangle2D) bounds.clone();
    044:    }
    045:
    046:    public void setBounds(Rectangle2D newBounds)
    047:    {
    048:       bounds = newBounds;
    049:    }
    050:
    051:    public Point2D getConnectionPoint(Point2D aPoint)
    052:    {
    053:       double slope = bounds.getHeight() / bounds.getWidth();
    054:       double x = bounds.getCenterX();
    055:       double y = bounds.getCenterY();
    056:       double ex = aPoint.getX() - x;
    057:       double ey = aPoint.getY() - y;
    058:
    059:       if (ex != 0 && -slope <= ey / ex && ey / ex <= slope)
    060:       {
    061:          // intersects at left or right boundary
    062:          if (ex > 0)
    063:          {
    064:             x = bounds.getMaxX();
    065:             y += (bounds.getWidth() / 2) * ey / ex;
    066:          }
    067:          else
    068:          {
    069:             x = bounds.getX();
    070:             y -= (bounds.getWidth() / 2) * ey / ex;
    071:          }
    072:       }
    073:       else if (ey != 0)
    074:       {
    075:          // intersects at top or bottom
    076:          if (ey > 0)
    077:          {
    078:             x += (bounds.getHeight() / 2) * ex / ey;
    079:             y = bounds.getMaxY();
    080:          }
    081:          else
    082:          {
    083:             x -= (bounds.getHeight() / 2) * ex / ey;
    084:             y = bounds.getY();
    085:          }
    086:       }
    087:       return new Point2D.Double(x, y);
    088:    }
    089:
    090:    private void writeObject(ObjectOutputStream out)
    091:       throws IOException
    092:    {
    093:       out.defaultWriteObject();
    094:       writeRectangularShape(out, bounds);
    095:    }
    096:
    097:    /**
    098:       A helper method to overcome the problem that the 2D shapes
    099:       aren't serializable. It writes x, y, width and height
    100:       to the stream.
    101:       @param out the stream
    102:       @param s the shape
    103:    */
    104:    private static void writeRectangularShape(
    105:       ObjectOutputStream out,
    106:       RectangularShape s)
    107:       throws IOException
    108:    {
    109:       out.writeDouble(s.getX());
    110:       out.writeDouble(s.getY());
    111:       out.writeDouble(s.getWidth());
    112:       out.writeDouble(s.getHeight());
    113:    }
    114:
    115:    private void readObject(ObjectInputStream in)
    116:       throws IOException, ClassNotFoundException
    117:    {
    118:       in.defaultReadObject();
    119:       bounds = new Rectangle2D.Double();
    120:       readRectangularShape(in, bounds);
    121:    }
    122:
    123:    /**
    124:       A helper method to overcome the problem that the 2D shapes
    125:       aren't serializable. It reads x, y, width and height
    126:       from the stream.
    127:       @param in the stream
    128:       @param s the shape whose frame is set from the stream values
    129:    */
    130:    private static void readRectangularShape(ObjectInputStream in,
    131:       RectangularShape s)
    132:       throws IOException
    133:    {
    134:       double x = in.readDouble();
    135:       double y = in.readDouble();
    136:       double width = in.readDouble();
    137:       double height = in.readDouble();
    138:       s.setFrame(x, y, width, height);
    139:    }
    140:
    141:    private transient Rectangle2D bounds;
    142: }