1
|
/*******************************************************************************
|
2
|
* Copyright (c) 2005, 2010 IBM Corporation and others.
|
3
|
* All rights reserved. This program and the accompanying materials
|
4
|
* are made available under the terms of the Eclipse Public License v1.0
|
5
|
* which accompanies this distribution, and is available at
|
6
|
* http://www.eclipse.org/legal/epl-v10.html
|
7
|
*
|
8
|
* Contributors:
|
9
|
* IBM Corporation - initial API and implementation
|
10
|
*******************************************************************************/
|
11
|
|
12
|
package org.eclipse.draw2d;
|
13
|
|
14
|
import org.eclipse.draw2d.geometry.Point;
|
15
|
import org.eclipse.draw2d.geometry.PointList;
|
16
|
|
17
|
/**
|
18
|
* Animates the routing of a connection. The animator will capture the effects
|
19
|
* of the connection's router, and the play back the placement of the routing,
|
20
|
* interpolating the intermediate routes.
|
21
|
* <P>
|
22
|
* To use a routing animator, hook it as a routing listener for the connection
|
23
|
* whose points are to be animated, by calling
|
24
|
* {@link PolylineConnection#addRoutingListener(RoutingListener)}. An animator
|
25
|
* is active only when the Animation utility is activated.
|
26
|
*
|
27
|
* @since 3.2
|
28
|
*/
|
29
|
public class RoutingAnimator extends Animator implements RoutingListener {
|
30
|
|
31
|
static final RoutingAnimator INSTANCE = new RoutingAnimator();
|
32
|
|
33
|
/**
|
34
|
* Constructs a routing animator for use with one or more connections. The
|
35
|
* default instance ({@link #getDefault()} can be used on any number of
|
36
|
* connections.
|
37
|
*
|
38
|
* @since 3.2
|
39
|
*/
|
40
|
protected RoutingAnimator() {
|
41
|
}
|
42
|
|
43
|
/**
|
44
|
* Overridden to sync initial and final states.
|
45
|
*
|
46
|
* @see Animator#playbackStarting(IFigure)
|
47
|
*/
|
48
|
public void playbackStarting(IFigure connection) {
|
49
|
reconcileStates((Connection) connection);
|
50
|
}
|
51
|
|
52
|
/**
|
53
|
* Returns the current state of the connection. Currently, this is a copy of
|
54
|
* the list of points. However this Object could change in future releases
|
55
|
* and should not be considered API.
|
56
|
*
|
57
|
* @see Animator#getCurrentState(IFigure)
|
58
|
*/
|
59
|
protected Object getCurrentState(IFigure connection) {
|
60
|
return ((Connection) connection).getPoints().getCopy();
|
61
|
}
|
62
|
|
63
|
/**
|
64
|
* Returns the default instance.
|
65
|
*
|
66
|
* @return the default instance
|
67
|
* @since 3.2
|
68
|
*/
|
69
|
public static RoutingAnimator getDefault() {
|
70
|
return INSTANCE;
|
71
|
}
|
72
|
|
73
|
/**
|
74
|
* Hooks invalidate for animation purposes.
|
75
|
*
|
76
|
* @see RoutingListener#invalidate(Connection)
|
77
|
*/
|
78
|
public final void invalidate(Connection conn) {
|
79
|
if (Animation.isInitialRecording())
|
80
|
Animation.hookAnimator(conn, this);
|
81
|
}
|
82
|
|
83
|
/**
|
84
|
* Plays back the interpolated state.
|
85
|
*
|
86
|
* @see Animator#playback(IFigure)
|
87
|
*/
|
88
|
protected boolean playback(IFigure figure) {
|
89
|
Connection conn = (Connection) figure;
|
90
|
|
91
|
PointList list1 = (PointList) Animation.getInitialState(this, conn);
|
92
|
PointList list2 = (PointList) Animation.getFinalState(this, conn);
|
93
|
if (list1 == null) {
|
94
|
conn.setVisible(false);
|
95
|
return true;
|
96
|
}
|
97
|
|
98
|
float progress = Animation.getProgress();
|
99
|
if (list1.size() == list2.size()) {
|
100
|
Point pt1 = new Point(), pt2 = new Point();
|
101
|
PointList points = conn.getPoints();
|
102
|
points.removeAllPoints();
|
103
|
for (int i = 0; i < list1.size(); i++) {
|
104
|
list1.getPoint(pt2, i);
|
105
|
list2.getPoint(pt1, i);
|
106
|
pt1.x = Math.round(pt1.x * progress + (1 - progress) * pt2.x);
|
107
|
pt1.y = Math.round(pt1.y * progress + (1 - progress) * pt2.y);
|
108
|
points.addPoint(pt1);
|
109
|
}
|
110
|
conn.setPoints(points);
|
111
|
}
|
112
|
return true;
|
113
|
}
|
114
|
|
115
|
/**
|
116
|
* Hooks post routing for animation purposes.
|
117
|
*
|
118
|
* @see RoutingListener#postRoute(Connection)
|
119
|
*/
|
120
|
public final void postRoute(Connection connection) {
|
121
|
if (Animation.isFinalRecording())
|
122
|
Animation.hookNeedsCapture(connection, this);
|
123
|
}
|
124
|
|
125
|
private void reconcileStates(Connection conn) {
|
126
|
PointList points1 = (PointList) Animation.getInitialState(this, conn);
|
127
|
PointList points2 = (PointList) Animation.getFinalState(this, conn);
|
128
|
|
129
|
if (points1 != null && points1.size() != points2.size()) {
|
130
|
Point p = new Point(), q = new Point();
|
131
|
|
132
|
int size1 = points1.size() - 1;
|
133
|
int size2 = points2.size() - 1;
|
134
|
|
135
|
int i1 = size1;
|
136
|
int i2 = size2;
|
137
|
|
138
|
double current1 = 1.0;
|
139
|
double current2 = 1.0;
|
140
|
|
141
|
double prev1 = 1.0;
|
142
|
double prev2 = 1.0;
|
143
|
|
144
|
while (i1 > 0 || i2 > 0) {
|
145
|
if (Math.abs(current1 - current2) < 0.1 && i1 > 0 && i2 > 0) {
|
146
|
// Both points are the same, use them and go on;
|
147
|
prev1 = current1;
|
148
|
prev2 = current2;
|
149
|
i1--;
|
150
|
i2--;
|
151
|
current1 = (double) i1 / size1;
|
152
|
current2 = (double) i2 / size2;
|
153
|
} else if (current1 < current2) {
|
154
|
// 2 needs to catch up
|
155
|
// current1 < current2 < prev1
|
156
|
points1.getPoint(p, i1);
|
157
|
points1.getPoint(q, i1 + 1);
|
158
|
|
159
|
p.x = (int) (((q.x * (current2 - current1) + p.x
|
160
|
* (prev1 - current2)) / (prev1 - current1)));
|
161
|
p.y = (int) (((q.y * (current2 - current1) + p.y
|
162
|
* (prev1 - current2)) / (prev1 - current1)));
|
163
|
|
164
|
points1.insertPoint(p, i1 + 1);
|
165
|
|
166
|
prev1 = prev2 = current2;
|
167
|
i2--;
|
168
|
current2 = (double) i2 / size2;
|
169
|
|
170
|
} else {
|
171
|
// 1 needs to catch up
|
172
|
// current2< current1 < prev2
|
173
|
|
174
|
points2.getPoint(p, i2);
|
175
|
points2.getPoint(q, i2 + 1);
|
176
|
|
177
|
p.x = (int) (((q.x * (current1 - current2) + p.x
|
178
|
* (prev2 - current1)) / (prev2 - current2)));
|
179
|
p.y = (int) (((q.y * (current1 - current2) + p.y
|
180
|
* (prev2 - current1)) / (prev2 - current2)));
|
181
|
|
182
|
points2.insertPoint(p, i2 + 1);
|
183
|
|
184
|
prev2 = prev1 = current1;
|
185
|
i1--;
|
186
|
current1 = (double) i1 / size1;
|
187
|
}
|
188
|
}
|
189
|
}
|
190
|
}
|
191
|
|
192
|
/**
|
193
|
* This callback is unused. Reserved for possible future use.
|
194
|
*
|
195
|
* @see RoutingListener#remove(Connection)
|
196
|
*/
|
197
|
public final void remove(Connection connection) {
|
198
|
}
|
199
|
|
200
|
/**
|
201
|
* Hooks route to intercept routing during animation playback.
|
202
|
*
|
203
|
* @see RoutingListener#route(Connection)
|
204
|
*/
|
205
|
public final boolean route(Connection conn) {
|
206
|
return Animation.isAnimating() && Animation.hookPlayback(conn, this);
|
207
|
}
|
208
|
|
209
|
/**
|
210
|
* This callback is unused. Reserved for possible future use.
|
211
|
*
|
212
|
* @see RoutingListener#setConstraint(Connection, Object)
|
213
|
*/
|
214
|
public final void setConstraint(Connection connection, Object constraint) {
|
215
|
}
|
216
|
|
217
|
}
|