1 package org.jcurl.demo.tactics;
2
3 import java.awt.BorderLayout;
4 import java.awt.Color;
5 import java.awt.geom.AffineTransform;
6 import java.awt.geom.Point2D;
7 import java.awt.geom.Rectangle2D;
8 import java.awt.geom.RectangularShape;
9 import java.util.IdentityHashMap;
10 import java.util.Iterator;
11 import java.util.Map;
12 import java.util.Map.Entry;
13
14 import javax.swing.event.ChangeEvent;
15
16 import org.apache.commons.logging.Log;
17 import org.jcurl.core.api.ComputedTrajectorySet;
18 import org.jcurl.core.api.Rock;
19 import org.jcurl.core.api.RockSet;
20 import org.jcurl.core.api.RockSetUtils;
21 import org.jcurl.core.api.RockType.Pos;
22 import org.jcurl.core.log.JCLoggerFactory;
23 import org.jcurl.core.ui.BroomPromptModel;
24 import org.jcurl.core.ui.ChangeManager;
25 import org.jcurl.core.ui.PosMemento;
26 import org.jcurl.math.R1RNFunction;
27 import org.jcurl.zui.piccolo.BroomPromptSimple;
28 import org.jcurl.zui.piccolo.PIceFactory;
29 import org.jcurl.zui.piccolo.PRockFactory;
30 import org.jcurl.zui.piccolo.PTrajectoryFactory;
31
32 import edu.umd.cs.piccolo.PCamera;
33 import edu.umd.cs.piccolo.PCanvas;
34 import edu.umd.cs.piccolo.PLayer;
35 import edu.umd.cs.piccolo.PNode;
36 import edu.umd.cs.piccolo.event.PBasicInputEventHandler;
37 import edu.umd.cs.piccolo.event.PInputEvent;
38 import edu.umd.cs.piccolo.event.PInputEventListener;
39 import edu.umd.cs.piccolo.util.PAffineTransform;
40 import edu.umd.cs.piccolo.util.PPaintContext;
41
42 public class TrajectoryPiccoloBean extends TrajectoryBean<PNode, PNode> {
43
44
45
46
47
48 private class MoveHandler extends PBasicInputEventHandler {
49 private PosMemento first = null;
50
51 private PNode climb(PNode node) {
52 for (;;) {
53 if (node.getPickable() && node.getAttribute(ATTR_IDX16) != null)
54 return node;
55 node = node.getParent();
56 if (node == null)
57 return null;
58 }
59 }
60
61 @SuppressWarnings("unchecked")
62 private PosMemento create(final PInputEvent e, final PNode node) {
63 final RockSet<Pos> rs = (RockSet<Pos>) node
64 .getAttribute(ATTR_ROCKSET);
65 final Point2D p = world.globalToLocal(e.getPosition());
66 if (log.isDebugEnabled())
67 log.debug(p);
68 return new PosMemento(rs, (Integer) node.getAttribute(ATTR_IDX16),
69 p);
70 }
71
72 @Override
73 public void mouseDragged(final PInputEvent e) {
74 final PNode node = climb(e.getPickedNode());
75 if (log.isDebugEnabled())
76 log.debug(node.getAttribute(ATTR_IDX16));
77 getChanger().temporary(create(e, node));
78 e.setHandled(true);
79 }
80
81 @Override
82 public void mouseEntered(final PInputEvent arg0) {
83 super.mouseEntered(arg0);
84 arg0.pushCursor(CURSOR);
85 }
86
87 @Override
88 public void mouseExited(final PInputEvent arg0) {
89 super.mouseExited(arg0);
90 arg0.popCursor();
91 }
92
93 @Override
94 public void mousePressed(final PInputEvent e) {
95 final PNode node = climb(e.getPickedNode());
96 if (log.isDebugEnabled())
97 log.debug(node.getAttribute(ATTR_IDX16));
98 final int i16 = (Integer) node.getAttribute(ATTR_IDX16);
99 final RockSet<Pos> ipos = getCurves().getInitialPos();
100 first = new PosMemento(ipos, i16, ipos.getRock(i16).p());
101 e.setHandled(true);
102 }
103
104 @Override
105 public void mouseReleased(final PInputEvent e) {
106 final PNode node = climb(e.getPickedNode());
107 if (log.isDebugEnabled())
108 log.debug(node.getAttribute(ATTR_IDX16));
109 getChanger().undoable(first, create(e, node));
110 e.setHandled(true);
111 }
112 }
113
114 private static final Log log = JCLoggerFactory
115 .getLogger(TrajectoryPiccoloBean.class);
116 private static final int major = 255;
117 private static final int minor = 64;
118 private static final long serialVersionUID = -4648771240323713217L;
119 private static final int WHEEL_DT = 0;
120 private static final double WHEEL_SCALE = 0.10;
121
122
123 private static void syncM2V(final ComputedTrajectorySet src, final int i16,
124 final PNode[] dst, final PTrajectoryFactory tf) {
125 syncM2V(src.getCurveStore().iterator(i16), i16, dst[i16], tf);
126 }
127
128
129 private static void syncM2V(
130 final Iterator<Entry<Double, R1RNFunction>> src, final int i16,
131 final PNode dst, final PTrajectoryFactory tf) {
132 if (log.isDebugEnabled())
133 log.debug("path " + i16);
134 tf.refresh(src, RockSet.isDark(i16), 0, 30, dst);
135 }
136
137
138 private static void syncM2V(final Rock<Pos> src, final PNode dst,
139 final long dt) {
140 if (src == null || dst == null) {
141 if (log.isDebugEnabled())
142 log.debug(src + " " + dst);
143 return;
144 }
145 if (log.isDebugEnabled())
146 log.debug("rock " + dst.getAttribute(ATTR_IDX16));
147 if (dt >= 0)
148 dst.animateToTransform(src.getAffineTransform(), dt);
149 else
150 dst.setTransform(src.getAffineTransform());
151 }
152
153 private final long AnimationMillis = 0;
154 private final BroomPromptSimple broom = new BroomPromptSimple();
155 private final PNode[] current = new PNode[RockSet.ROCKS_PER_SET];
156 private final PNode[] initial = new PNode[RockSet.ROCKS_PER_SET];
157 private final PInputEventListener mouse = new MoveHandler();
158 private final PCanvas panel;
159 private final PNode[] path = new PNode[RockSet.ROCKS_PER_SET];
160
161 private final Map<Rock<Pos>, PNode> r2n = new IdentityHashMap<Rock<Pos>, PNode>();
162 private final PNode rocks;
163 private final PTrajectoryFactory tf = new PTrajectoryFactory.Fancy();
164 private final PNode world;
165
166 public TrajectoryPiccoloBean() {
167 setVisible(false);
168 broom.setModel(tt);
169 panel = new PCanvas();
170 panel.addInputEventListener(new PInputEventListener() {
171 public void processEvent(final PInputEvent evt, final int i) {
172 if (evt.isMouseWheelEvent()) {
173
174 final int c = evt.getWheelRotation();
175 final double s = Math.pow(
176 1D - WHEEL_SCALE * Math.signum(c), Math.abs(c));
177 final Point2D p = evt.getPosition();
178 final PCamera cam = evt.getCamera();
179 if (WHEEL_DT <= 0)
180 cam.scaleViewAboutPoint(s, p.getX(), p.getY());
181 else {
182 final PAffineTransform t = cam.getViewTransform();
183 t.scaleAboutPoint(s, p.getX(), p.getY());
184 cam.animateViewToTransform(t, WHEEL_DT);
185 }
186 tmpViewPort = cam.getViewBounds();
187 }
188 }
189 });
190
191 panel.setAnimatingRenderQuality(PPaintContext.HIGH_QUALITY_RENDERING);
192 panel.setInteractingRenderQuality(PPaintContext.HIGH_QUALITY_RENDERING);
193 setLayout(new BorderLayout());
194 add(panel, BorderLayout.CENTER);
195
196
197 world = new PNode();
198
199 world.addChild(new PIceFactory.Fancy().newInstance());
200
201 final PNode init = new PNode();
202 final PNode curr = new PNode();
203 final PNode paths = new PNode();
204 rocks = new PNode();
205 final RockSet<Pos> home = RockSetUtils.allHome();
206 final RockSet<Pos> out = RockSetUtils.allOut();
207 final PRockFactory iniRf = new PRockFactory.Fancy(minor);
208 final PRockFactory curRf = new PRockFactory.Fancy(major);
209 for (int i16 = RockSet.ROCKS_PER_SET - 1; i16 >= 0; i16--) {
210
211 PNode n;
212 init.addChild(n = initial[i16] = iniRf.newInstance(i16));
213 n.setPickable(true);
214 n.addInputEventListener(mouse);
215
216
217 curr.addChild(n = current[i16] = curRf.newInstance(i16));
218 n.addAttribute(ATTR_TRIGGER_CURVE_UPDATE, true);
219 n.setChildrenPickable(false);
220
221
222 paths.addChild(path[i16] = new PNode());
223 }
224 rocks.addChild(paths);
225 rocks.addChild(init);
226 rocks.addChild(curr);
227 rocks.addChild(broom);
228 rocks.setVisible(false);
229 world.addChild(rocks);
230
231
232 world.setTransform(AffineTransform.getScaleInstance(1, -1));
233
234 panel.getLayer().addChild(world);
235 panel.setBackground(super.getBackground());
236 setVisible(true);
237 }
238
239 @Override
240 public BroomPromptModel getBroom() {
241 return broom.getModel();
242 }
243
244 PLayer getIceLayer() {
245 return panel.getLayer();
246 }
247
248 @Override
249 public RectangularShape getZoom() {
250 if (super.getZoom() == null)
251 return panel.getCamera().getViewBounds();
252 return super.getZoom();
253 }
254
255 @Override
256 public void setBackground(final Color bg) {
257 panel.setBackground(bg);
258 super.setBackground(bg);
259 }
260
261 @Override
262 public void setChanger(final ChangeManager changer) {
263 super.setChanger(changer);
264 broom.setChanger(changer);
265 }
266
267 @Override
268 public void setCurves(final ComputedTrajectorySet curves) {
269
270 if (this.curves != null) {
271 removeCL(this.curves.getInitialPos());
272 removeCL(this.curves.getCurrentPos());
273 }
274 this.curves = curves;
275 r2n.clear();
276 if (this.curves != null) {
277 final RockSet<Pos> ip = this.curves.getInitialPos();
278 final RockSet<Pos> cp = this.curves.getCurrentPos();
279 addCL(ip);
280 addCL(cp);
281 for (int i16 = RockSet.ROCKS_PER_SET - 1; i16 >= 0; i16--) {
282 syncM2V(ip, i16, initial[i16]);
283 syncM2V(cp, i16, current[i16]);
284 syncM2V(getCurves(), i16, path, tf);
285 }
286 }
287 tt.init(this.curves);
288 rocks.setVisible(this.curves != null);
289 }
290
291 public void setZoom(final RectangularShape viewport, int transitionMillis) {
292 if (transitionMillis < 0)
293 transitionMillis = 333;
294 final Rectangle2D r;
295 if (viewport instanceof Rectangle2D)
296 r = (Rectangle2D) viewport;
297 else
298 r = new Rectangle2D.Double(viewport.getX(), viewport.getY(),
299 viewport.getWidth(), viewport.getHeight());
300 tmpViewPort = (Rectangle2D) r.clone();
301 panel.getCamera().animateViewToCenterBounds(r, true, transitionMillis);
302 }
303
304
305 public void stateChanged(final ChangeEvent e) {
306 if (e.getSource() instanceof Rock) {
307
308 final Rock<Pos> r = (Rock<Pos>) e.getSource();
309 final PNode n = r2n.get(r);
310 syncM2V(r, n, AnimationMillis);
311
312
313 if (!Boolean.TRUE.equals(n.getAttribute(ATTR_TRIGGER_CURVE_UPDATE)))
314 return;
315 final int i16 = (Integer) n.getAttribute(ATTR_IDX16);
316 syncM2V(getCurves(), i16, path, tf);
317 } else if (log.isDebugEnabled())
318 log.debug("Unconsumed event from " + e.getSource());
319 }
320
321
322
323
324
325
326
327
328
329 private PNode syncM2V(final RockSet<Pos> src, final int i16, final PNode dst) {
330 final Rock<Pos> r = src.getRock(i16);
331 syncM2V(r, dst, 0);
332 dst.addAttribute(ATTR_ROCKSET, src);
333 dst.addAttribute(ATTR_ROCK, r);
334 dst.addAttribute(ATTR_IDX16, i16);
335 r2n.put(r, dst);
336 return dst;
337 }
338 }