View Javadoc

1   /* -------------------------------------------------------------------
2    * Java source file for the class GArrow
3    * 
4    * Copyright (c), 2003, Masahiro Takatsuka.
5    * All Rights Researved.
6    * 
7    * Original Author: Masahiro Takatsuka (masa@jbeans.net)
8    * $Author: takatsukam $
9    * 
10   * $Date: 2004/03/03 11:53:06 $
11   * 
12   * $Id: GArrow.java,v 1.3 2004/03/03 11:53:06 takatsukam Exp $
13   * 
14   * Reference:		Document no:
15   * ___				___
16   * 
17   * To Do:
18   * ___
19   * 
20  ------------------------------------------------------------------- */
21  
22  /* --------------------------- Package ---------------------------- */
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                      Implementation of class GArrow                     
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  		 * setTailRadiusRatio(float)
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  		 * setTailHeightRatio(float)
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  		 * setHeadRadiusRatio(float)
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  		 * setHeadHeightRatio(float)
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;// tail radius
103 	
104 	/* ------------------------ not serialized ------------------------ */
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 	/* -------------------------- serialized -------------------------- */
116 	private float baseRatio = 1.0f;// tail radius	
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 		// translate these geoms about tail's height along y axis.
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);		// Tail is the 0th child
316 		
317 		tg = createArrowHead();
318 		setTransformCapabilities(tg);
319 		bg.insertChild(tg, HEAD);		// Head is the 1st child
320 
321 		this.refArrow = bg;
322 	}
323 
324 	private void setShape3DCapabilities(Shape3D shape3d) {
325 		// set capabilites before return it.
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 	/* --------------------- begin: GlyphSource --------------------- */
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 		// get transformGroup of tail
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 		// get transformGroup of head
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 		// get transformGroup of tail
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 		// get transformGroup of head
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 	* Returns an array containing indices of essential setters.
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 		// get transformGroup of tail
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 		// get transformGroup of tail
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 }