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