comparison dwtx/draw2d/RoutingAnimator.d @ 98:95307ad235d9

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