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