View Javadoc
1   /*
2    * Copyright (c) 2005, The JUNG Authors
3    * All rights reserved.
4    *
5    * This software is open-source under the BSD license; see either "license.txt"
6    * or https://github.com/jrtom/jung/blob/master/LICENSE for a description.
7    *
8    * Created on Aug 23, 2005
9    */
10  package edu.uci.ics.jung.visualization.renderers;
11  
12  import java.awt.Shape;
13  import java.awt.geom.AffineTransform;
14  import java.awt.geom.GeneralPath;
15  import java.awt.geom.Line2D;
16  import java.awt.geom.PathIterator;
17  import java.awt.geom.Point2D;
18  
19  import edu.uci.ics.jung.visualization.RenderContext;
20  
21  public class CenterEdgeArrowRenderingSupport<V,E> implements EdgeArrowRenderingSupport<V,E> {
22  
23      public AffineTransform getArrowTransform(RenderContext<V,E> rc, Shape edgeShape, Shape vertexShape) {
24      	GeneralPath path = new GeneralPath(edgeShape);
25          float[] seg = new float[6];
26          Point2D p1=null;
27          Point2D p2=null;
28          AffineTransform at = new AffineTransform();
29          // count the segments.
30          int middleSegment = 0;
31          int current = 0;
32          for(PathIterator i=path.getPathIterator(null,1); !i.isDone(); i.next()) {
33          	current++;
34          }
35          middleSegment = current/2;
36          // find the middle segment
37          current = 0;
38          for(PathIterator i=path.getPathIterator(null,1); !i.isDone(); i.next()) {
39          	current++;
40          	int ret = i.currentSegment(seg);
41          	if(ret == PathIterator.SEG_MOVETO) {
42          		p2 = new Point2D.Float(seg[0],seg[1]);
43          	} else if(ret == PathIterator.SEG_LINETO) {
44          		p1 = p2;
45          		p2 = new Point2D.Float(seg[0],seg[1]);
46          	}
47          	if(current > middleSegment) { // done
48          		at = getArrowTransform(rc, new Line2D.Float(p1,p2),vertexShape);
49          		break;
50          	}
51  
52          } 
53          return at;
54      }
55  
56      public AffineTransform getReverseArrowTransform(RenderContext<V,E> rc, Shape edgeShape, Shape vertexShape) {
57          return getReverseArrowTransform(rc, edgeShape, vertexShape, true);
58      }
59              
60      /**
61       * Returns a transform to position the arrowhead on this edge shape at the
62       * point where it intersects the passed vertex shape.
63       * 
64       * @param rc the rendering context used for rendering the arrow
65       * @param edgeShape the shape used to draw the edge
66       * @param vertexShape the shape used to draw the vertex
67       * @param passedGo (ignored in this implementation)
68       */
69      public AffineTransform getReverseArrowTransform(RenderContext<V,E> rc, Shape edgeShape, Shape vertexShape,
70              boolean passedGo) {
71      	GeneralPath path = new GeneralPath(edgeShape);
72          float[] seg = new float[6];
73          Point2D p1=null;
74          Point2D p2=null;
75          AffineTransform at = new AffineTransform();
76          // count the segments.
77          int middleSegment = 0;
78          int current = 0;
79          for(PathIterator i=path.getPathIterator(null,1); !i.isDone(); i.next()) {
80          	current++;
81          }
82          middleSegment = current/2;
83          // find the middle segment
84          current = 0;
85          for(PathIterator i=path.getPathIterator(null,1); !i.isDone(); i.next()) {
86          	current++;
87          	int ret = i.currentSegment(seg);
88          	if(ret == PathIterator.SEG_MOVETO) {
89          		p2 = new Point2D.Float(seg[0],seg[1]);
90          	} else if(ret == PathIterator.SEG_LINETO) {
91          		p1 = p2;
92          		p2 = new Point2D.Float(seg[0],seg[1]);
93          	}
94          	if(current > middleSegment) { // done
95          		at = getReverseArrowTransform(rc, new Line2D.Float(p1,p2),vertexShape);
96          		break;
97          	}
98          }
99          return at;
100     }
101 
102     public AffineTransform getArrowTransform(RenderContext<V,E> rc, Line2D edgeShape, Shape vertexShape) {
103         
104         // find the midpoint of the edgeShape line, and use it to make the transform
105         Line2D left = new Line2D.Float();
106         Line2D right = new Line2D.Float();
107         this.subdivide(edgeShape, left, right);
108         edgeShape = right;
109         float dx = (float) (edgeShape.getX1()-edgeShape.getX2());
110         float dy = (float) (edgeShape.getY1()-edgeShape.getY2());
111         double atheta = Math.atan2(dx,dy)+Math.PI/2;
112         AffineTransform at = 
113             AffineTransform.getTranslateInstance(edgeShape.getX1(), edgeShape.getY1());
114         at.rotate(-atheta);
115         return at;
116     }
117 
118     protected AffineTransform getReverseArrowTransform(RenderContext<V,E> rc,
119     		Line2D edgeShape, Shape vertexShape) {
120         // find the midpoint of the edgeShape line, and use it to make the transform
121         Line2D left = new Line2D.Float();
122         Line2D right = new Line2D.Float();
123         this.subdivide(edgeShape, left, right);
124         edgeShape = right;
125         float dx = (float) (edgeShape.getX1()-edgeShape.getX2());
126         float dy = (float) (edgeShape.getY1()-edgeShape.getY2());
127         // calculate the angle for the arrowhead
128         double atheta = Math.atan2(dx,dy)-Math.PI/2;
129         AffineTransform at = AffineTransform.getTranslateInstance(edgeShape.getX1(),edgeShape.getY1());
130         at.rotate(-atheta);
131         return at;
132     }
133     
134     /**
135      * divide a Line2D into 2 new Line2Ds that are returned
136      * in the passed left and right instances, if non-null
137      * @param src the line to divide
138      * @param left the left side, or null
139      * @param right the right side, or null
140      */
141     protected void subdivide(Line2D src,
142             Line2D left,
143             Line2D right) {
144         double x1 = src.getX1();
145         double y1 = src.getY1();
146         double x2 = src.getX2();
147         double y2 = src.getY2();
148         
149         double mx = x1 + (x2-x1)/2.0;
150         double my = y1 + (y2-y1)/2.0;
151         if (left != null) {
152             left.setLine(x1, y1, mx, my);
153         }
154         if (right != null) {
155             right.setLine(mx, my, x2, y2);
156         }
157     }
158 }