1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.jcurl.demo.tactics;
21
22 import java.awt.BorderLayout;
23 import java.awt.RenderingHints;
24 import java.awt.event.MouseEvent;
25 import java.awt.geom.AffineTransform;
26 import java.awt.geom.Point2D;
27 import java.awt.geom.RectangularShape;
28 import java.util.IdentityHashMap;
29 import java.util.Iterator;
30 import java.util.Map;
31 import java.util.Map.Entry;
32
33 import javax.swing.event.ChangeEvent;
34 import javax.swing.event.ChangeListener;
35
36 import org.apache.commons.logging.Log;
37 import org.jcurl.core.api.ComputedTrajectorySet;
38 import org.jcurl.core.api.Rock;
39 import org.jcurl.core.api.RockSet;
40 import org.jcurl.core.api.RockSetUtils;
41 import org.jcurl.core.api.RockType.Pos;
42 import org.jcurl.core.log.JCLoggerFactory;
43 import org.jcurl.core.ui.BroomPromptModel;
44 import org.jcurl.core.ui.ChangeManager;
45 import org.jcurl.core.ui.PosMemento;
46 import org.jcurl.demo.tactics.sg.AnimateAffine;
47 import org.jcurl.demo.tactics.sg.BroomPromptScenario;
48 import org.jcurl.demo.tactics.sg.SGIceFactory;
49 import org.jcurl.demo.tactics.sg.SGRockFactory;
50 import org.jcurl.demo.tactics.sg.SGTrajectoryFactory;
51 import org.jcurl.math.R1RNFunction;
52
53 import com.sun.scenario.scenegraph.JSGPanel;
54 import com.sun.scenario.scenegraph.SGComposite;
55 import com.sun.scenario.scenegraph.SGGroup;
56 import com.sun.scenario.scenegraph.SGNode;
57 import com.sun.scenario.scenegraph.SGRenderCache;
58 import com.sun.scenario.scenegraph.SGTransform;
59 import com.sun.scenario.scenegraph.SGComposite.OverlapBehavior;
60 import com.sun.scenario.scenegraph.SGTransform.Affine;
61 import com.sun.scenario.scenegraph.event.SGMouseAdapter;
62
63
64
65
66
67 public class TrajectoryScenarioBean extends TrajectoryBean<Affine, SGGroup>
68 implements ChangeListener {
69 private class MoveHandler extends SGMouseAdapter {
70 private PosMemento first = null;
71 private final Point2D tmp = new Point2D.Double(0, 0);
72
73 @SuppressWarnings("unchecked")
74 private PosMemento create(final MouseEvent e, final SGNode node) {
75 final RockSet<Pos> rs = (RockSet<Pos>) node
76 .getAttribute(ATTR_ROCKSET);
77 final Point2D p = dc2wc.globalToLocal(e.getPoint(), tmp);
78 if (log.isDebugEnabled())
79 log.debug(p);
80 return new PosMemento(rs, (Integer) node.getAttribute(ATTR_IDX16),
81 p);
82 }
83
84 @Override
85 public void mouseDragged(final MouseEvent e, final SGNode node) {
86 if (log.isDebugEnabled())
87 log.debug(node.getAttribute(ATTR_IDX16));
88 getChanger().temporary(create(e, node));
89 }
90
91 @Override
92 public void mousePressed(final MouseEvent e, final SGNode node) {
93 if (log.isDebugEnabled())
94 log.debug(node.getAttribute(ATTR_IDX16));
95 final int i16 = (Integer) node.getAttribute(ATTR_IDX16);
96 final RockSet<Pos> ipos = getCurves().getInitialPos();
97 first = new PosMemento(ipos, i16, ipos.getRock(i16).p());
98 }
99
100 @Override
101 public void mouseReleased(final MouseEvent e, final SGNode node) {
102 if (log.isDebugEnabled())
103 log.debug(node.getAttribute(ATTR_IDX16));
104 getChanger().undoable(first, create(e, node));
105 }
106 }
107
108 private static final boolean DoCacheRocks = true;
109 private static final Log log = JCLoggerFactory
110 .getLogger(TrajectoryScenarioBean.class);
111 private static final long serialVersionUID = 6661957210899967106L;
112
113 private static Affine createSceneRock(final int i16, final int opacity) {
114 SGNode rock = new SGRockFactory.Fancy().newInstance(i16);
115 if (DoCacheRocks) {
116 final SGRenderCache rc = new SGRenderCache();
117 rc.setChild(rock);
118 rc
119 .setInterpolationHint(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
120 rock = rc;
121 }
122 return SGTransform.createAffine(new AffineTransform(), rock);
123 }
124
125
126 private static void syncM2V(final ComputedTrajectorySet src, final int i16,
127 final SGGroup[] dst, final SGTrajectoryFactory tf) {
128 syncM2V(src.getCurveStore().iterator(i16), i16, dst[i16], tf);
129
130 }
131
132
133 private static void syncM2V(
134 final Iterator<Entry<Double, R1RNFunction>> src, final int i16,
135 final SGGroup dst, final SGTrajectoryFactory tf) {
136 if (log.isDebugEnabled())
137 log.debug("path " + i16);
138 tf.refresh(src, RockSet.isDark(i16), 0, 30, dst);
139 }
140
141
142 private static void syncM2V(final Rock<Pos> src, final Affine dst) {
143 if (src == null || dst == null) {
144 if (log.isDebugEnabled())
145 log.debug(src + " " + dst);
146 return;
147 }
148 if (log.isDebugEnabled())
149 log.debug("rock " + dst.getAttribute(ATTR_IDX16));
150 dst.setAffine(src.getAffineTransform());
151 }
152
153 private final BroomPromptScenario broom = new BroomPromptScenario();
154 private final Affine[] current = new Affine[RockSet.ROCKS_PER_SET];
155 private final Affine dc2wc;
156 private final Affine[] initial = new Affine[RockSet.ROCKS_PER_SET];
157 private final MoveHandler mouse = new MoveHandler();
158
159 private final SGComposite opa_r0 = new SGComposite();
160 private final SGComposite opa_r1 = new SGComposite();
161 private final SGComposite opa_t0 = new SGComposite();
162 private final JSGPanel panel;
163 private final SGGroup[] path = new SGGroup[RockSet.ROCKS_PER_SET];
164
165 private final Map<Rock<Pos>, Affine> r2n = new IdentityHashMap<Rock<Pos>, Affine>();
166 private final SGGroup rocks = new SGGroup();
167 private final transient SGTrajectoryFactory tf = new SGTrajectoryFactory.Fancy();
168 private final Affine zoom;
169
170 public TrajectoryScenarioBean() {
171 setVisible(false);
172 broom.setModel(tt);
173 panel = new JSGPanel();
174 setLayout(new BorderLayout());
175 add(panel, BorderLayout.CENTER);
176
177 final SGGroup world = new SGGroup();
178 world.add(new SGIceFactory.Fancy().newInstance());
179
180
181 final SGGroup r0 = new SGGroup();
182 final SGGroup r1 = new SGGroup();
183 final SGGroup pa = new SGGroup();
184
185 final RockSet<Pos> home = RockSetUtils.allHome();
186 final RockSet<Pos> out = RockSetUtils.allOut();
187 for (int i16 = RockSet.ROCKS_PER_SET - 1; i16 >= 0; i16--) {
188 Affine n = createSceneRock(home, i16, 255);
189 n.setMouseBlocker(true);
190 n.addMouseListener(mouse);
191 n.setCursor(CURSOR);
192 r0.add(initial[i16] = n);
193 r1.add(current[i16] = n = createSceneRock(out, i16, 255));
194 n.putAttribute(ATTR_TRIGGER_CURVE_UPDATE, true);
195 pa.add(path[i16] = new SGGroup());
196 }
197 if (false) {
198 rocks.add(pa);
199 rocks.add(r0);
200 rocks.add(r1);
201 } else {
202 opa_r0.setChild(r0);
203 opa_r0.setOpacity(64.0F / 255.0F);
204 opa_r0.setOverlapBehavior(OverlapBehavior.LAYER);
205
206 opa_r1.setChild(r1);
207 opa_r1.setOverlapBehavior(OverlapBehavior.LAYER);
208
209 opa_t0.setChild(pa);
210 opa_t0.setMouseBlocker(true);
211 opa_t0.setOverlapBehavior(OverlapBehavior.LAYER);
212 opa_t0.setOpacity(100.0F / 255.0F);
213
214 rocks.add(opa_t0);
215 rocks.add(opa_r0);
216 rocks.add(opa_r1);
217 }
218 rocks.add(broom.getScene());
219 rocks.setVisible(false);
220 world.add(rocks);
221
222
223 final AffineTransform rightHand = AffineTransform.getScaleInstance(1,
224 -1);
225 zoom = SGTransform.createAffine(new AffineTransform(),
226 dc2wc = SGTransform.createAffine(rightHand, world));
227 broom.setDc2wc(dc2wc);
228 panel.setScene(zoom);
229 setVisible(true);
230 }
231
232 private Affine createSceneRock(final RockSet<Pos> pos, final int i16,
233 final int opacity) {
234 return syncM2V(pos, i16, createSceneRock(i16, opacity));
235 }
236
237
238
239
240
241
242
243
244 @Override
245 public BroomPromptModel getBroom() {
246 return broom.getModel();
247 }
248
249 Affine getDc2Wc() {
250 return dc2wc;
251 }
252
253 @Override
254 public void setChanger(final ChangeManager changer) {
255 super.setChanger(changer);
256 broom.setChanger(changer);
257 }
258
259 @Override
260 public void setCurves(final ComputedTrajectorySet curves) {
261
262 if (this.curves != null) {
263 removeCL(this.curves.getInitialPos());
264 removeCL(this.curves.getCurrentPos());
265 }
266 this.curves = curves;
267 r2n.clear();
268 if (this.curves != null) {
269 final RockSet<Pos> ip = this.curves.getInitialPos();
270 final RockSet<Pos> cp = this.curves.getCurrentPos();
271 addCL(ip);
272 addCL(cp);
273 for (int i16 = RockSet.ROCKS_PER_SET - 1; i16 >= 0; i16--) {
274 syncM2V(ip, i16, initial[i16]);
275 syncM2V(cp, i16, current[i16]);
276 syncM2V(getCurves(), i16, path, tf);
277 }
278 }
279 tt.init(this.curves);
280 rocks.setVisible(this.curves != null);
281 }
282
283 public void setZoom(final RectangularShape viewport,
284 final int transitionMillis) {
285 AnimateAffine.animateToCenterBounds(zoom, this.getBounds(),
286 tmpViewPort = viewport, transitionMillis);
287 }
288
289 public void stateChanged(final ChangeEvent e) {
290 if (e.getSource() instanceof Rock) {
291
292 final Rock<Pos> r = (Rock<Pos>) e.getSource();
293 final Affine n = r2n.get(r);
294 syncM2V(r, n);
295
296
297 if (!Boolean.TRUE.equals(n.getAttribute(ATTR_TRIGGER_CURVE_UPDATE)))
298 return;
299 final int i16 = (Integer) n.getAttribute(ATTR_IDX16);
300 syncM2V(getCurves(), i16, path, tf);
301 } else if (log.isDebugEnabled())
302 log.debug("Unconsumed event from " + e.getSource());
303 }
304
305
306
307
308
309
310
311
312
313 private Affine syncM2V(final RockSet<Pos> src, final int i16,
314 final Affine dst) {
315 final Rock<Pos> r = src.getRock(i16);
316 syncM2V(r, dst);
317 dst.putAttribute(ATTR_ROCKSET, src);
318 dst.putAttribute(ATTR_ROCK, r);
319 dst.putAttribute(ATTR_IDX16, i16);
320 r2n.put(r, dst);
321 return dst;
322 }
323 }