001 package nl.cwi.sen1.gui.plugin.prefusedot;
002
003 import java.awt.Shape;
004 import java.awt.geom.AffineTransform;
005 import java.awt.geom.GeneralPath;
006 import java.awt.geom.Point2D;
007 import java.awt.geom.Rectangle2D;
008
009 import prefuse.Constants;
010 import prefuse.render.EdgeRenderer;
011 import prefuse.util.GraphicsLib;
012 import prefuse.visual.EdgeItem;
013 import prefuse.visual.VisualItem;
014
015 public class DotEdgeRenderer extends EdgeRenderer {
016 protected static Point2D start = new Point2D.Float();
017 protected static Point2D end = new Point2D.Float();
018
019 public DotEdgeRenderer(int edgeType, int arrowType) {
020 super(edgeType, arrowType);
021 }
022
023 protected boolean onDotLocation(VisualItem item) {
024 return item.getX() == item.getInt(DotAdapter.DOT_X)
025 && item.getY() == item.getInt(DotAdapter.DOT_Y);
026 }
027
028 protected Shape makeCurvedEdge(Point2D start, Point2D end, Point2D[] points) {
029 Point2D from = start;
030 Point2D to = from;
031
032 GeneralPath gp = new GeneralPath(GeneralPath.WIND_NON_ZERO);
033 gp.moveTo((float) from.getX(), (float) from.getY());
034
035 int i;
036 for (i = 1; i + 2 < points.length; i += 3) {
037 Point2D cp1 = points[i];
038 Point2D cp2 = points[i + 1];
039 Point2D cur = points[i + 2];
040
041 from = cp1;
042 to = cur;
043
044 gp.curveTo((float) cp1.getX(), (float) cp1.getY(), (float) cp2
045 .getX(), (float) cp2.getY(), (float) cur.getX(),
046 (float) cur.getY());
047
048 }
049
050
051 if (i < points.length) {
052 from = to;
053 to = points[points.length - 1];
054 gp.lineTo((float) to.getX(), (float) to.getY());
055 }
056
057 gp.lineTo((float) end.getX(), (float) end.getY());
058
059 // TODO: remove this hack that is used to retrieve the last
060 // direction of
061 // the edge
062 start.setLocation(from);
063
064
065 return gp;
066 }
067
068 protected Shape getArrowShape(Point2D start, Point2D end, VisualItem item) {
069 int i = getIntersectionPoint(item, start, end, m_isctPoints);
070 if (i > 0) {
071 end = m_isctPoints[0];
072 }
073 AffineTransform at = getArrowTrans(start, end, 1);
074 return at.createTransformedShape(m_arrowHead);
075 }
076
077 protected static void getAlignedPoint(Point2D p, Rectangle2D r, int xAlign,
078 int yAlign) {
079 double x = r.getX(), y = r.getY(), w = r.getWidth(), h = r.getHeight();
080 if (xAlign == Constants.CENTER) {
081 x = x + (w / 2);
082 } else if (xAlign == Constants.RIGHT) {
083 x = x + w;
084 }
085 if (yAlign == Constants.CENTER) {
086 y = y + (h / 2);
087 } else if (yAlign == Constants.BOTTOM) {
088 y = y + h;
089 }
090 p.setLocation(x, y);
091 }
092
093 /**
094 * @copy super.getRawShape() but with support for arrows to different shapes than boxes,
095 * and without support for prefuse's curved edges.
096 */
097 protected Shape getStraightEdge(VisualItem item) {
098 EdgeItem edge = (EdgeItem) item;
099 VisualItem item1 = edge.getSourceItem();
100 VisualItem item2 = edge.getTargetItem();
101
102 getAlignedPoint(m_tmpPoints[0], item1.getBounds(), m_xAlign1, m_yAlign1);
103 getAlignedPoint(m_tmpPoints[1], item2.getBounds(), m_xAlign2, m_yAlign2);
104 m_curWidth = (float) (m_width * getLineWidth(item));
105
106 // create the arrow head, if needed
107 EdgeItem e = (EdgeItem) item;
108 if (e.isDirected() && m_edgeArrow != Constants.EDGE_ARROW_NONE) {
109 Shape arrow = getArrowShape(m_tmpPoints[0], m_tmpPoints[1], item2);
110 setRenderType(RENDER_TYPE_DRAW_AND_FILL);
111 m_curArrow = arrow;
112 } else {
113 m_curArrow = null;
114 }
115
116 // create the edge shape
117 Shape shape = null;
118 double n1x = m_tmpPoints[0].getX();
119 double n1y = m_tmpPoints[0].getY();
120 double n2x = m_tmpPoints[1].getX();
121 double n2y = m_tmpPoints[1].getY();
122 m_line.setLine(n1x, n1y, n2x, n2y);
123 shape = m_line;
124
125 // return the edge shape
126 return shape;
127 }
128
129 protected Shape getRawShape(VisualItem item) {
130 EdgeItem edge = (EdgeItem) item;
131 VisualItem item1 = edge.getSourceItem();
132 VisualItem item2 = edge.getTargetItem();
133
134 // If the nodes are not on their original dot positions, the curved
135 // edge degenerates to a straight edge.
136 if (!onDotLocation(item1) || !onDotLocation(item2)) {
137 return getStraightEdge(item);
138 }
139
140 // Find the middle of the start and end nodes
141 getAlignedPoint(start, item1.getBounds(), Constants.CENTER,
142 Constants.CENTER);
143 getAlignedPoint(end, item2.getBounds(), Constants.CENTER,
144 Constants.CENTER);
145
146 // Retrieve the dot curve points data
147 Point2D[] points = (Point2D[]) item.get(DotAdapter.DOT_CURVE_POINTS);
148 if (points == null) {
149 return getStraightEdge(item);
150 }
151
152 // now construct the curved edge
153 Shape shape = makeCurvedEdge(start, end, points);
154 AffineTransform at = getTransform(item);
155 shape = (at == null) ? shape : at.createTransformedShape(shape);
156
157 // create the arrow head, if needed
158 // TODO: fix this hack that takes care of arrow size offsets
159 // end.setLocation(end.getX(), end.getY() - m_arrowHeight);
160 Shape arrow = getArrowShape(start, end, item2);
161 setRenderType(RENDER_TYPE_DRAW_AND_FILL);
162 m_curArrow = arrow;
163
164 setRenderType(RENDER_TYPE_DRAW);
165 return shape;
166 }
167
168 protected int getIntersectionPoint(VisualItem item, Point2D from, Point2D to,
169 Point2D[] intersection) {
170 String shapeName = item.getString(DotAdapter.DOT_SHAPE);
171 int i;
172
173 if (shapeName != null) {
174 if (shapeName.equals("box")) {
175 i = computeBoxIntersectionPoint(item, from, to, intersection);
176 } else if (shapeName.equals("circle")) {
177 i = computeCircleIntersectionPoint(item, from, to, intersection);
178 } else if (shapeName.equals("ellipse")) {
179 i = computeEllipseIntersectionPoint(item, from, to,
180 intersection);
181 } else {
182 i = computeBoxIntersectionPoint(item, from, to, intersection);
183 }
184 } else {
185 i = computeBoxIntersectionPoint(item, from, to, intersection);
186 }
187
188 return i;
189 }
190
191 protected int computeEllipseIntersectionPoint(VisualItem item, Point2D from,
192 Point2D to, Point2D[] intersection) {
193 int i = computeBoxIntersectionPoint(item, from, to, intersection);
194 Rectangle2D bounds = item.getBounds();
195 float x = (float) (intersection[0].getX() - bounds.getCenterX());
196 float y = (float) (intersection[0].getY() - bounds.getCenterY());
197 float xrad = (float) (bounds.getWidth() / 2);
198 float yrad = (float) (bounds.getHeight() / 2);
199 float phi = x != 0 ? (float) Math.atan(Math
200 .abs((y / yrad) / (x / xrad))) : 0;
201 x = (float) Math.cos(phi) * xrad * (x < 0 ? -1 : 1);
202 y = (float) Math.sin(phi) * yrad * (y < 0 ? -1 : 1);
203 intersection[0].setLocation(x + bounds.getCenterX(), y
204 + bounds.getCenterY());
205 return i;
206 }
207
208 protected int computeCircleIntersectionPoint(VisualItem item, Point2D from,
209 Point2D to, Point2D[] intersection) {
210 return computeEllipseIntersectionPoint(item, from, to, intersection);
211 }
212
213 protected int computeBoxIntersectionPoint(VisualItem item, Point2D from,
214 Point2D to, Point2D[] intersection) {
215 int i = GraphicsLib.intersectLineRectangle(from, to, item.getBounds(),
216 intersection);
217 return i;
218 }
219 }