1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package net.jbeans.j3d.modeler.scene.glyph;
24
25 /* ------------------ Import classes (packages) ------------------- *//package-summary/html">class="comment"> ------------------ Import classes (packages) ------------------- *//package-summary.html">class="comment">/* ------------------ Import classes (packages) ------------------- *//package-summary.html">class="comment"> ------------------ Import classes (packages) ------------------- */
26 import java.beans.*;
27 import java.io.*;
28 import java.lang.reflect.*;
29 import javax.media.j3d.*;
30 import javax.vecmath.*;
31 import com.sun.j3d.utils.geometry.*;
32
33 import net.jbeans.j3d.modeler.scene.*;
34
35
36
37
38 /***
39 * GArrow is a glyph source which generatees an arrow geometry object.
40 *
41 * @version $Revision: 1.3 $
42 * @author Masahiro Takatsuka (masa@jbeans.net)
43 * @see GlyphSource, Serializable
44 */
45
46 public class GArrow implements GlyphSource, Serializable {
47 private static Method[] sSetMethods;
48 private static int[] sEssentials;
49 static {
50 setSetMethods();
51 }
52
53 private static void setSetMethods() {
54 Class clazz = GArrow.class;
55 sSetMethods = new Method[4];
56 sEssentials = new int[0];
57 Method m = null;
58
59
60
61
62 try {
63 m = clazz.getMethod("setTailRadiusRatio", new Class[] {java.lang.Float.TYPE});
64 sSetMethods[0] = m;
65 } catch (Exception e) {
66 sSetMethods[0] = null;
67 }
68
69
70
71
72 try {
73 m = clazz.getMethod("setTailHeightRatio", new Class[] {java.lang.Float.TYPE});
74 sSetMethods[1] = m;
75 } catch (Exception e) {
76 sSetMethods[1] = null;
77 }
78
79
80
81
82 try {
83 m = clazz.getMethod("setHeadRadiusRatio", new Class[] {java.lang.Float.TYPE});
84 sSetMethods[2] = m;
85 } catch (Exception e) {
86 sSetMethods[2] = null;
87 }
88
89
90
91
92 try {
93 m = clazz.getMethod("setHeadHeightRatio", new Class[] {java.lang.Float.TYPE});
94 sSetMethods[3] = m;
95 } catch (Exception e) {
96 sSetMethods[3] = null;
97 }
98 }
99
100 private static final int TAIL = 0;
101 private static final int HEAD = 1;
102 private static final float BASE_RADIUS = 0.5f;
103
104
105 transient private Cone sRefCone;
106 transient private Cylinder sRefCylinder;
107 transient private PropertyChangeSupport changes;
108 transient private float headHeight;
109 transient private float headRadius;
110 transient private float tailHeight;
111 transient private float tailRadius;
112 transient private BranchGroup refArrow;
113 transient private Transform3D tmpT3D = new Transform3D();
114
115
116 private float baseRatio = 1.0f;
117 private float baseHeadHeightRatio = 10.0f;
118 private float baseHeadRadiusRatio = 2.0f;
119 private float baseTailHeightRatio = 5.0f;
120 private float baseTailRadiusRatio = 1.0f;
121
122 private float headHeightRatio;
123 private float headRadiusRatio;
124 private float tailHeightRatio;
125 private float tailRadiusRatio;
126
127 public GArrow() {
128 super();
129 initialize();
130 }
131
132 private void initialize() {
133 this.changes = new PropertyChangeSupport(this);
134 setDefaultValues();
135 createRefArrow();
136 }
137
138 public void addPropertyChangeListener(PropertyChangeListener l) {
139 this.changes.addPropertyChangeListener(l);
140 }
141
142 public void removePropertyChangeListener(PropertyChangeListener l) {
143 this.changes.removePropertyChangeListener(l);
144 }
145
146 private void setDefaultValues() {
147 this.headHeightRatio = 1.0f;
148 this.headRadiusRatio = 1.0f;
149 this.tailHeightRatio = 1.0f;
150 this.tailRadiusRatio = 1.0f;
151 }
152
153 public void setBaseRatio(float r) {
154 r = (r <= 0.0f) ? 1.0f : r;
155 float old = this.baseRatio;
156 this.baseRatio = r;
157 createRefArrow();
158 this.changes.firePropertyChange("baseRatio",
159 new Float(old),
160 new Float(this.baseRatio));
161 }
162
163 public float getBaseRatio() {
164 return this.baseRatio;
165 }
166
167 public void setBaseHeadHeightRatio(float r) {
168 r = (r <= 0.0f) ? 1.0f : r;
169 float old = this.baseHeadHeightRatio;
170 this.baseHeadHeightRatio = r;
171 createRefArrow();
172 this.changes.firePropertyChange("baseHeadHeightRatio",
173 new Float(old),
174 new Float(this.baseHeadHeightRatio));
175 }
176
177 public float getBaseHeadHeightRatio() {
178 return this.baseHeadHeightRatio;
179 }
180
181 public void setBaseHeadRadiusRatio(float r) {
182 r = (r <= 0.0f) ? 1.0f : r;
183 float old = this.baseHeadRadiusRatio;
184 this.baseHeadRadiusRatio = r;
185 createRefArrow();
186 this.changes.firePropertyChange("baseHeadRadiusRatio",
187 new Float(old),
188 new Float(this.baseHeadRadiusRatio));
189 }
190
191 public float getBaseHeadRadiusRatio() {
192 return this.baseHeadRadiusRatio;
193 }
194
195 public void setBaseTailHeightRatio(float r) {
196 r = (r <= 0.0f) ? 1.0f : r;
197 float old = this.baseTailHeightRatio;
198 this.baseTailHeightRatio = r;
199 createRefArrow();
200 this.changes.firePropertyChange("baseTailHeightRatio",
201 new Float(old),
202 new Float(this.baseTailHeightRatio));
203 }
204
205 public float getBaseTailHeightRatio() {
206 return this.baseTailHeightRatio;
207 }
208
209 public void setBaseTailRadiusRatio(float r) {
210 r = (r <= 0.0f) ? 1.0f : r;
211 float old = this.baseTailRadiusRatio;
212 this.baseTailRadiusRatio = r;
213 createRefArrow();
214 this.changes.firePropertyChange("baseTailRadiusRatio",
215 new Float(old),
216 new Float(this.baseTailRadiusRatio));
217 }
218
219 public float getBaseTailRadiusRatio() {
220 return this.baseTailRadiusRatio;
221 }
222
223 public void setHeadHeightRatio(float r) {
224 r = (r <= 0.0f) ? 1.0f : r;
225 this.headHeightRatio = r;
226 }
227
228 public float getHeadHeightRatio() {
229 return this.headHeightRatio;
230 }
231
232 public void setHeadRadiusRatio(float r) {
233 r = (r <= 0.0f) ? 1.0f : r;
234 this.headRadiusRatio = r;
235 }
236
237 public float getHeadRadiusRatio() {
238 return this.headRadiusRatio;
239 }
240
241 public void setTailHeightRatio(float r) {
242 r = (r <= 0.0f) ? 1.0f : r;
243 this.tailHeightRatio = r;
244 }
245
246 public float getTailHeightRatio() {
247 return this.tailHeightRatio;
248 }
249
250 public void setTailRadiusRatio(float r) {
251 r = (r <= 0.0f) ? 1.0f : r;
252 this.tailRadiusRatio = r;
253 }
254
255 public float getTailRadiusRatio() {
256 return this.tailRadiusRatio;
257 }
258
259 private TransformGroup createArrowTail() {
260 this.tailRadius = BASE_RADIUS * this.baseTailRadiusRatio * this.baseRatio * 1.0f;
261 this.tailHeight = BASE_RADIUS * this.baseTailHeightRatio * this.baseRatio * 1.0f;
262 Cylinder cyl = new Cylinder(this.tailRadius, this.tailHeight);
263
264 Shape3D s3d = cyl.getShape(Cylinder.BODY);
265 setShape3DCapabilities(s3d);
266 Geometry geom = s3d.getGeometry();
267 setGeometryCapabilities(geom);
268
269 s3d = cyl.getShape(Cylinder.TOP);
270 setShape3DCapabilities(s3d);
271 geom = s3d.getGeometry();
272 setGeometryCapabilities(geom);
273
274 s3d = cyl.getShape(Cylinder.BOTTOM);
275 setShape3DCapabilities(s3d);
276 geom = s3d.getGeometry();
277 setGeometryCapabilities(geom);
278
279 TransformGroup tailTransformGroup = new TransformGroup();
280 tailTransformGroup.addChild(cyl);
281
282 return tailTransformGroup;
283 }
284
285 private TransformGroup createArrowHead() {
286 this.headRadius = BASE_RADIUS * this.baseHeadRadiusRatio * this.baseRatio * 1.0f;
287 this.headHeight = BASE_RADIUS * this.baseHeadHeightRatio * this.baseRatio * 1.0f;
288
289 Cone cone = new Cone(this.headRadius, this.headHeight);
290 Shape3D s3d = cone.getShape(Cone.BODY);
291 setShape3DCapabilities(s3d);
292 Geometry geom = s3d.getGeometry();
293 setGeometryCapabilities(geom);
294
295 s3d = cone.getShape(Cone.CAP);
296 setShape3DCapabilities(s3d);
297 geom = s3d.getGeometry();
298 setGeometryCapabilities(geom);
299
300
301 Transform3D headTransform = new Transform3D();
302 headTransform.set(new Vector3f(0.0f,
303 (this.tailHeight + this.headHeight)/2.0f,
304 0.0f));
305 TransformGroup headTransformGroup = new TransformGroup(headTransform);
306 headTransformGroup.addChild(cone);
307
308 return headTransformGroup;
309 }
310
311 private void createRefArrow() {
312 BranchGroup bg = new BranchGroup();
313 TransformGroup tg = createArrowTail();
314 setTransformCapabilities(tg);
315 bg.insertChild(tg, TAIL);
316
317 tg = createArrowHead();
318 setTransformCapabilities(tg);
319 bg.insertChild(tg, HEAD);
320
321 this.refArrow = bg;
322 }
323
324 private void setShape3DCapabilities(Shape3D shape3d) {
325
326 shape3d.setCapability(Node.ALLOW_BOUNDS_READ);
327 shape3d.setCapability(Node.ALLOW_BOUNDS_WRITE);
328 shape3d.setCapability(Node.ALLOW_AUTO_COMPUTE_BOUNDS_READ);
329 shape3d.setCapability(Node.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE);
330 shape3d.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
331 shape3d.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
332 shape3d.setCapability(Shape3D.ALLOW_COLLISION_BOUNDS_READ);
333 shape3d.setCapability(Shape3D.ALLOW_COLLISION_BOUNDS_WRITE);
334 shape3d.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
335 shape3d.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
336 }
337
338 private void setGeometryCapabilities(Geometry geom) {
339 geom.setCapability(GeometryArray.ALLOW_COUNT_READ);
340 geom.setCapability(GeometryArray.ALLOW_FORMAT_READ);
341 geom.setCapability(GeometryArray.ALLOW_COORDINATE_READ);
342 geom.setCapability(GeometryArray.ALLOW_COORDINATE_WRITE);
343 geom.setCapability(GeometryArray.ALLOW_NORMAL_READ);
344 geom.setCapability(GeometryArray.ALLOW_NORMAL_WRITE);
345 geom.setCapability(IndexedGeometryArray.ALLOW_COORDINATE_INDEX_READ);
346 geom.setCapability(IndexedGeometryArray.ALLOW_COORDINATE_INDEX_WRITE);
347 geom.setCapability(IndexedGeometryArray.ALLOW_NORMAL_INDEX_READ);
348 geom.setCapability(IndexedGeometryArray.ALLOW_NORMAL_INDEX_WRITE);
349 }
350
351 private void setTransformCapabilities(TransformGroup tg) {
352 tg.setCapability(Group.ALLOW_CHILDREN_EXTEND);
353 tg.setCapability(Group.ALLOW_CHILDREN_READ);
354 tg.setCapability(Group.ALLOW_CHILDREN_WRITE);
355 tg.setCapability(Group.ALLOW_COLLISION_BOUNDS_READ);
356 tg.setCapability(Group.ALLOW_COLLISION_BOUNDS_WRITE);
357 tg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
358 tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
359 }
360
361 private void setBranchGroupCapabilities(BranchGroup bg) {
362 bg.setCapability(Group.ALLOW_CHILDREN_EXTEND);
363 bg.setCapability(Group.ALLOW_CHILDREN_READ);
364 bg.setCapability(Group.ALLOW_CHILDREN_WRITE);
365 bg.setCapability(Group.ALLOW_COLLISION_BOUNDS_READ);
366 bg.setCapability(Group.ALLOW_COLLISION_BOUNDS_WRITE);
367 }
368
369
370 /***
371 * Returns javax.media.3d.Shape3D object.
372 */
373 synchronized public Node getNode() {
374 BranchGroup bg = (BranchGroup) this.refArrow.cloneTree(true);
375 setBranchGroupCapabilities(bg);
376
377
378 TransformGroup tg = (TransformGroup) bg.getChild(TAIL);
379 tg.getTransform(this.tmpT3D);
380 this.tmpT3D.setScale(new Vector3d(this.tailRadiusRatio,
381 this.tailHeightRatio,
382 this.tailRadiusRatio));
383
384 tg.setTransform(this.tmpT3D);
385
386
387 tg = (TransformGroup) bg.getChild(HEAD);
388 tg.getTransform(this.tmpT3D);
389 this.tmpT3D.setScale(new Vector3d(this.headRadiusRatio,
390 this.headHeightRatio,
391 this.headRadiusRatio));
392 double tailHeight = this.tailHeight * this.tailHeightRatio;
393 double headHeight = this.headHeight * this.headHeightRatio;
394 this.tmpT3D.setTranslation(new Vector3d(0.0f,
395 (tailHeight + headHeight)/2.0f,
396 0.0f));
397 tg.setTransform(this.tmpT3D);
398
399 return bg;
400 }
401
402 /***
403 * Updates the specified Shape3D object.
404 */
405 synchronized public Node updateNode(Node node) {
406 if (! (node instanceof BranchGroup)) {
407 return node;
408 }
409
410 BranchGroup bg = (BranchGroup) node;
411
412
413 TransformGroup tg = (TransformGroup) bg.getChild(TAIL);
414 tg.getTransform(this.tmpT3D);
415 this.tmpT3D.setScale(new Vector3d(this.tailRadiusRatio,
416 this.tailHeightRatio,
417 this.tailRadiusRatio));
418 tg.setTransform(this.tmpT3D);
419
420
421 tg = (TransformGroup) bg.getChild(HEAD);
422 tg.getTransform(this.tmpT3D);
423 this.tmpT3D.setScale(new Vector3d(this.headRadiusRatio,
424 this.headHeightRatio,
425 this.headRadiusRatio));
426 double tailHeight = this.tailHeight * this.tailHeightRatio;
427 double headHeight = this.headHeight * this.headHeightRatio;
428 this.tmpT3D.setTranslation(new Vector3d(0.0f,
429 (tailHeight + headHeight)/2.0f,
430 0.0f));
431 tg.setTransform(this.tmpT3D);
432
433 return node;
434 }
435
436 /***
437 * Returns an array containing methods to set data to construct
438 * a glyph source.
439 */
440 public Method[] getSetMethods() {
441 return sSetMethods;
442 }
443
444
445
446
447 public int[] getEssentials() {
448 return sEssentials;
449 }
450
451 /***
452 * Returns javax.media.3d.Appearance object.
453 */
454 public Appearance getAppearanceOfNode(Node node) {
455 if (! (node instanceof BranchGroup)) {
456 return null;
457 }
458
459 BranchGroup bg = (BranchGroup) node;
460
461
462 TransformGroup tg = (TransformGroup) bg.getChild(TAIL);
463 Cylinder cyl = (Cylinder) tg.getChild(0);
464 return cyl.getShape(Cylinder.BODY).getAppearance();
465 }
466
467 /***
468 * Updates the specified Appearance object.
469 */
470 public void setAppearanceOfNode(Node node, Appearance appearance) {
471 if (! (node instanceof BranchGroup)) {
472 return;
473 }
474
475 BranchGroup bg = (BranchGroup) node;
476
477
478 TransformGroup tg = (TransformGroup) bg.getChild(TAIL);
479 Cylinder cyl = (Cylinder) tg.getChild(TAIL);
480 cyl.setAppearance(appearance);
481
482 tg = (TransformGroup) bg.getChild(HEAD);
483 Cone cone = (Cone) tg.getChild(0);
484 cone.setAppearance(appearance);
485 }
486 }