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: }