View Javadoc
1   /* -------------------------------------------------------------------
2    * Java source file for the class GlyphModeler
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: GlyphModeler.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;
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.awt.*;
27  import java.beans.*;
28  import java.io.*;
29  import java.lang.reflect.*;
30  import java.util.*;
31  import javax.media.j3d.*;
32  import javax.vecmath.*;
33  import com.sun.j3d.utils.geometry.*;
34  
35  import net.jbeans.bean.*;
36  import net.jbeans.data.converter.*;
37  import net.jbeans.lang.*;
38  import net.jbeans.lang.reflect.*;
39  import net.jbeans.j3d.data.*;
40  
41  import net.jbeans.util.debug.*;
42  
43  /*====================================================================
44                   Implementation of class GlyphModeler                 
45  ====================================================================*/
46  /***
47   * GlyphModeler is a class that creates a javax.media.j3d.BranchGroup
48   * object (more specifically net.jbeans.j3d.scenegraph.BranchGroup), which
49   * contains a set of geometry (glyph) objects.
50   * 
51   * @version $Revision: 1.3 $
52   * @author Masahiro Takatsuka (masa@jbeans.net)
53   * @see SceneModeler
54   * @see Pretender, IntexedValueSetter, PropertyChangeListener, Serializable
55   */
56  
57  public class GlyphModeler extends SceneModeler implements Pretender, IndexedValueSetter, PropertyChangeListener, Serializable {
58    	private static final boolean DEBUG = Debug.getDebugFlag(GlyphModeler.class);
59  
60  	private static final int TOTAL_INDEX = 10;
61  	private static final int PX = 0; // position x
62  	private static final int PY = 1; // position y
63  	private static final int PZ = 2; // position z
64  	private static final int SCALE = 3;	// scale
65  	private static final int OX = 4; // orientation x
66  	private static final int OY = 5; // orientation y
67  	private static final int OZ = 6; // orientation z
68  	private static final int COLOR = 7;	// color
69  	private static final int ALPHA = 8;	// transparency
70  	private static final int USER_DATA = 9;	// user data.
71  
72  	/*
73  	* Essential attributes to construct a grid surface.
74  	*/
75  	public static final int[] ESSENTIALS = {PX, PY, PZ};
76  	
77  	/* ------------------------ not serialized ------------------------ */
78  	transient private PropertyChangeSupport changes;
79  
80  	transient private GlyphSource source;
81  	
82  	// for Pretender
83  	transient private Vector getters;
84  	transient private Vector setters;
85  	transient private DataConverter[] converters;
86  	transient private String[] argTypeStrs;
87  	transient private int[] sourceEssentials;
88  	transient private String[] setterNames;
89  	//transient private String[] getterNames;	
90  	transient private Object[] entryArray;
91  
92  	transient private int entryNum;
93  	transient private int oldEntryNum;	
94  	
95  	transient private double[][] common = new double[TOTAL_INDEX][];
96  	transient private Object userData; // must be an array.
97  	transient private net.jbeans.j3d.scenegraph.BranchGroup topBranch;
98  	transient private TransformGroup[] tGroups;
99  	transient private Node[] nodes;
100 	transient private Vector3d trans = new Vector3d();
101 	transient private Matrix3d rot = new Matrix3d();
102 	transient private Transform3D t3d = new Transform3D();
103 
104 	transient private boolean colorAtSource = false;
105 		
106 	// these are for translation
107 	transient private Matrix3d mat1 = new Matrix3d();
108 	transient private Matrix3d mat2 = new Matrix3d();
109 	transient private Matrix3d matv1 = new Matrix3d();
110 	transient private Vector3d yAxis = new Vector3d(0.0, 1.0, 0.0);
111 	transient private Vector3d dstVector = new Vector3d();
112 
113 	// for color
114 	transient private Color3f colorTmp = new Color3f();
115 
116 	/* -------------------------- serialized -------------------------- */
117 	private int transparencyMode = TransparencyAttributes.FASTEST;
118 	private int shadeModel = ColoringAttributes.FASTEST;	
119 	private ColorLookupTable colorLT;
120 	private boolean lightingEnable = true;
121 	//private boolean lightingEnable = false;
122 	private double defaultScale;
123 	private Color defaultColor;	
124 	
125 	/***
126 	 * Construct a new GlyphModeler.
127 	 */
128 	public GlyphModeler() {
129 		super();
130 		this.changes = new PropertyChangeSupport(this);
131 		addPropertyChangeListener(this);
132 		this.topBranch = new net.jbeans.j3d.scenegraph.BranchGroup();
133 		initialize();
134 	}
135 	
136 	private void initialize() {
137 		// for Pretender
138 		this.source = null;
139 		this.getters = new Vector();
140 		this.setters = new Vector();
141 		this.converters = null;
142 		this.argTypeStrs = null;		
143 		this.setterNames = new String[] {};
144 		//this.getterNames = new String[] {};
145 
146 		this.entryArray = new Object[0];
147 		this.colorLT = new ColorLookupTable();
148 		this.entryNum = -1;
149 		this.oldEntryNum = -1;		
150 		this.defaultScale = 1.0;
151 		this.defaultColor = Color.white;
152 	}
153 
154 	private void reset() {
155 		clearScene();			// remove the topBranch
156 		this.topBranch = new net.jbeans.j3d.scenegraph.BranchGroup();
157 		this.tGroups = new net.jbeans.j3d.transform.TransformGroup[this.entryNum];
158 		this.nodes = new Node[this.entryNum];		
159 	}
160 
161 	/***
162 	* Sets the default color used to color glyphs.
163 	*
164 	* @param color the defautl color.
165 	*/
166 	public void setDefaultColor(Color color) {
167 		Color oldValue = this.defaultColor;
168 		this.defaultColor = color;
169 		if (DEBUG) {
170 			System.out.println("color = " + color);
171 		}
172 		Object source = (this.source == null) ? this : (Object) this.source;
173 		propertyChange(new PropertyChangeEvent(source, "defaultColor", this.defaultColor, oldValue));
174 	}
175 
176 	/***
177 	* Returns the defautl color.
178 	*
179 	* @return the default color.
180 	*/
181 	public Color getDefaultColor() {
182 		return this.defaultColor;
183 	}
184 
185 	/***
186 	* Sets the default scaling factor.  All the glyphs are scaled before
187 	* individual scaling is applied to each glyph.
188 	*
189 	* @param scale the default scaling factor.
190 	*/
191 	public void setDefaultScale(double scale) {
192 		Double oldValue = new Double(this.defaultScale);
193 		this.defaultScale = scale;
194 		if (DEBUG) {
195 			System.out.println("scale = " + scale);
196 		}
197 		Double newValue = new Double(this.defaultScale);
198 		Object source = (this.source == null) ? this : (Object) this.source;
199 		propertyChange(new PropertyChangeEvent(source, "defaultScale", newValue, oldValue));
200 	}
201 
202 	/***
203 	* Returns the defautl scaling factor.
204 	*/
205 	public double getDefaultScale() {
206 		return this.defaultScale;
207 	}
208 
209 	/***
210 	* Sets the shading model.
211 	*/
212 	public void setShadeModel(int model) {
213 		Integer oldValue = new Integer(this.shadeModel);
214 		this.shadeModel = model;
215 
216 		Object source = (this.source == null) ? this : (Object) this.source;
217 		propertyChange(new PropertyChangeEvent(source, "shadeModel", new Integer(this.shadeModel), oldValue));
218 	}
219 
220 	/***
221 	* Returns the current shading model.
222 	*/
223 	public int getShadeModel() {
224 		return this.shadeModel;
225 	}
226 
227 	/***
228 	* Sets the transparency Mode.
229 	*
230 	* @param mode the transparency mode.
231 	*/
232 	public void setTransparencyMode(int mode) {
233 		Integer oldValue = new Integer(this.transparencyMode);
234 		this.transparencyMode = mode;
235 
236 		Object source = (this.source == null) ? this : (Object) this.source;
237 		propertyChange(new PropertyChangeEvent(source, "transparencyMode", new Integer(this.transparencyMode), oldValue));		
238 	}
239 
240 	/***
241 	* Returns the current transparency mode.
242 	*/
243 	public int getTransparencyMode() {
244 		return this.transparencyMode;
245 	}
246 
247 	/***
248 	* Sets the color lookup table.
249 	*/
250 	public void setColorLookupTable(ColorLookupTable lt) {
251 		this.colorLT = lt;
252 	}
253 
254 	public ColorLookupTable getColorLookupTable() {
255 		return this.colorLT;
256 	}
257 
258 	public void setLightingEnable(boolean b) {
259 		Boolean oldValue = new Boolean(this.lightingEnable);
260 		this.lightingEnable = b;
261 
262 		Object source = (this.source == null) ? this : (Object) this.source;
263 		propertyChange(new PropertyChangeEvent(source, "lightingEnable", new Boolean(this.lightingEnable), oldValue));		
264 	}
265 
266 	public boolean getLightingEnable() {
267 		return this.lightingEnable;
268 	}
269 	
270 	/***
271 	 * Serialization methods
272 	 */
273 	private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
274 		s.defaultReadObject();
275 		initialize();
276 	}
277 	
278 	public void addPropertyChangeListener(PropertyChangeListener l) {
279 		this.changes.addPropertyChangeListener(l);
280 	}
281 
282 	public void removePropertyChangeListener(PropertyChangeListener l) {
283 		this.changes.removePropertyChangeListener(l);		
284 	}
285 	
286 	private synchronized void setCommonValueAt(int index, Object value) {
287 		this.common[index] = (double[]) value;
288 
289 		/*
290 		  get number of entries (entryNum).
291 		  If the number of entry changes, it will be picked up here.
292 		  And it causes to model instead of update.
293 		*/
294 		if (value != null) {
295 			this.entryNum = this.common[index].length;
296 		}
297 		setSceneData();		
298 	}
299 
300 	public void setXCoordinates(double[] x) {
301 		setCommonValueAt(PX, x);
302 	}
303 	public void setYCoordinates(double[] y) {
304 		setCommonValueAt(PY, y);
305 	}
306 	public void setZCoordinates(double[] z) {
307 		setCommonValueAt(PZ, z);
308 	}
309 	public void setScales(double[] scale) {
310 		setCommonValueAt(SCALE, scale);
311 	}
312 	public void setXOrientations(double[] x) {
313 		setCommonValueAt(OX, x);
314 	}
315 	public void setYOrientations(double[] y) {
316 		setCommonValueAt(OY, y);
317 	}
318 	public void setZOrientations(double[] z) {
319 		setCommonValueAt(OZ, z);
320 	}
321 	public void setColors(double[] color) {
322 		setCommonValueAt(COLOR, color);
323 	}
324 	public void setTransparency(double[] alpha) {
325 		setCommonValueAt(ALPHA, alpha);
326 	}
327 
328 	public void setUserData(Object userData) {
329 		if (!ClassUtil.isArray(userData)) {
330 			return;
331 		}
332 		this.userData = userData;
333 		if (this.userData != null) {
334 			this.entryNum = Array.getLength(this.userData);
335 		}
336 	}
337 	
338 	/* --------------------- begin : Pretender ---------------------- */
339 	private void setPropertyChangeListener(Object source) {
340 		// if the source bean implements add/remove propertyChangeListener
341 		try {
342 			Class[] args = {PropertyChangeListener.class};
343 			Class beanClass = source.getClass();
344 			Method adder = beanClass.getMethod("addPropertyChangeListener", args);
345 			Object[] arg = {this};
346 			adder.invoke(source, arg);
347 		} catch (Exception ex) {
348 			// NOP
349 		}
350 	}
351 
352 	public void setSource(Object source) {
353 		Object oldSource = this.source;
354 		initialize();				// clear the Vector;
355 
356 		if (source == null) {
357 			return;
358 		}
359 		if ( !(source instanceof GlyphSource)) {
360 			setupIndexedValueAccessors();			
361 			return;
362 		}
363 		this.source = (GlyphSource) source;
364 		/*
365 		* 
366 		* Masahiro Takatsuka/2001-Oct-13
367 		*/
368 		setSetters(this.source.getSetMethods());
369 		int[] sessentials = this.source.getEssentials();
370 		this.sourceEssentials = (sessentials == null) ? new int[] {}: sessentials;
371 		
372 //  		Class clazz = source.getClass();
373 //  		try {
374 //  			// get methods from BeanInfo using getMethodDescriptors.
375 //  			BeanInfo binfo = BeanInfoFinder.getBeanInfo(clazz);
376 //  			MethodDescriptor[] mds = binfo.getMethodDescriptors();
377 //  			for (int i = 0; i < mds.length; i++) {
378 //  				Method method = mds[i].getMethod();
379 //  				String methodName = method.getName();
380 //  				if (methodName.startsWith(SETTER_STR)) {
381 //  					/*
382 //  					 * In this version, only the method
383 //  					 * with one arg is supportetd.
384 //  					 */
385 //  					Class[] paramTypes = method.getParameterTypes();
386 //  					if (paramTypes.length == 1) {
387 //  						addSetter(method);
388 //  					}
389 //  				} else if (methodName.startsWith(GETTER_STR)) {
390 //  					/*
391 //  					 * null-arg and return something.
392 //  					 */
393 //  					Class[] paramTypes = method.getParameterTypes();
394 //  					Class returnType = method.getReturnType();
395 //  					if ((returnType != Void.TYPE) &&
396 //  						(paramTypes.length == 0)) {
397 //  						addGetter(method);
398 //  					}
399 //  				}
400 //  			}
401 //  		} catch (IntrospectionException ex) {
402 //  			ex.printStackTrace();
403 //  		}
404 		setupIndexedValueAccessors();
405 
406 		// add this to source's property listener list.
407 		setPropertyChangeListener(this.source);
408 
409 		Object[] args = new Object[] {new Double(1.0)};
410 		if (ClassUtil.respondsToMethod(this.source, "setColor", args)) {
411 			this.colorAtSource = true;
412 		}
413 		
414 		this.changes.firePropertyChange("source", oldSource, this.source);
415 	}
416 	
417 	public Object getSource() {
418 		return this.source;
419 	}
420 	
421 	public Method[] getSetters() {
422 		Method[] array = new Method[] {};
423 		return (Method[]) this.setters.toArray(array);
424 	}
425 
426 	public void setSetters(Method[] methods) {
427 		this.setters.clear();
428 		if (methods == null || methods.length == 0) {
429 			return;
430 		}
431 		int size = methods.length;
432 		for (int i = 0; i < size; i++) {
433 			this.setters.add(methods[i]);
434 		}
435 	}
436 
437 	public Method getSetterAt(int index) {
438 		return (Method) this.setters.get(index);
439 	}
440 	
441 	public void setSetterAt(int index, Method method) {
442 		this.setters.add(index, method);		
443 	}
444 
445 	private void addSetter(Method method) {
446 		this.setters.add(method);
447 	}
448 
449 	private void addGetter(Method method) {
450 		this.getters.add(method);
451 	}
452 	
453 	public Method[] getGetters() {
454 		Method[] array = new Method[] {};		
455 		return (Method[]) this.getters.toArray(array);
456 	}
457 	
458 	public void setGetters(Method[] methods) {
459 		if (this.getters.size() > 0) {
460 			this.getters.clear();
461 		}
462 		int size = methods.length;
463 		for (int i = 0; i < size; i++) {
464 			this.getters.add(methods[i]);
465 		}
466 	}
467 
468 	public Method getGetterAt(int index) {
469 		return (Method) this.getters.get(index);		
470 	}
471 	
472 	public void setGetterAt(int index, Method method) {
473 		this.getters.add(index, method);		
474 	}
475 	
476 	private void setupIndexedValueAccessors() {
477 		int size = this.setters.size();
478 		Method method = null;
479 		this.setterNames = new String[size];
480 		this.entryArray = new Object[size];
481 
482 		for (int i = 0; i < size; i++) {
483 			method = (Method) this.setters.get(i);
484 			if (method == null) {
485 				continue;
486 			}
487 			String methodName = ClassUtil.formatMethodSignature(method);
488 			int idx = methodName.indexOf(SETTER_STR);
489 			if (DEBUG) {
490 				System.out.println("setting: " + methodName + " at: " + i);
491 			}
492 			setSetterNameAt(i, SETTER_PREFIX + methodName.substring(idx + SETTER_STR.length()));
493 		}
494 		//  		size = this.getters.size();
495 		//  		this.getterNames = new String[size];		
496 		//  		for (int i = 0; i < size; i++) {
497 		//  			method = (Method) this.getters.get(i);
498 		//  			String methodName = ClassUtil.formatMethodSignature(method);
499 		//  			int idx = methodName.indexOf(GETTER_STR);
500 		//  			setGetterNameAt(i, GETTER_PREFIX + methodName.substring(idx + GETTER_STR.length()));			
501 		//  		}
502 	}
503 	/* ---------------------- end : Pretender ----------------------- */
504 
505 	/* ----------------- begin : IndexedValueSetter ----------------- */
506 	/***
507 	 * returns the number of available index.
508 	 */
509 	public int getNumberOfSetter() {
510 		return this.setterNames.length;
511 	}
512 	
513 	/***
514 	 * sets the number of index.
515 	 */
516 	public void setNumberOfSetter(int num) {
517 		// NOP
518 	}
519 
520 	/***
521 	 * set the setter method name for the specified index.
522 	 */
523 	public void setSetterNameAt(int index, String name) {
524 		this.setterNames[index] = name;
525 	}
526 	
527 	/***
528 	 * get the setter method name for the specified index.
529 	 */
530 	public final String getSetterNameAt(int index) {
531 		return (this.setterNames != null) ? this.setterNames[index] : null;
532 	}
533 	
534 	/***
535 	 * Method to set value at the specified index.
536 	 */
537 	public void setValueAt(int index, Object value) {
538 		this.entryArray[index] = value;
539 		setSceneData();
540 	}
541 
542 	public Method getIndexedValueSetter() {
543 		Class[] argTypes = new Class[]{Integer.TYPE, Object.class};
544 		return ClassUtil.getMethod(this, "setValueAt", argTypes);
545 	}
546 	
547 	/* ------------------ end : IndexedValueSetter ------------------ */
548 	
549 	/* ---------------- begin: PropertyChangeListener ----------------- */
550 	public void propertyChange(PropertyChangeEvent evt) {
551 		Object src = evt.getSource();
552 
553 		if (src != this.source) {
554 			return;
555 		}
556 		Object oldValue = evt.getOldValue();
557 		Object newValue = evt.getNewValue();
558 		if (newValue.equals(oldValue)) {
559 			return;
560 		}
561 		
562 		/*
563 		* This will forse setData() to call model() instead of update();
564 		* Masahiro Takatsuka/2001-Jul-07
565 		*/
566 		this.oldEntryNum = -1;
567 		setSceneData();
568 	}
569 	
570 	/* ----------------- end: PropertyChangeListener ------------------ */
571 
572 	public void set(int length, Object array, String methodname) {
573 		Method method = findMethod(methodname);
574 		if (method == null) {
575 			return;
576 		}
577 		if (this.source != null) {					
578 			for (int i = 0; i < length; i++) {
579 				Object[] args = {java.lang.reflect.Array.get(array, i)};
580 				
581 				try {
582 					ClassUtil.makeObjectPerform(this.source,
583 												  method.getName(),
584 												  args
585 												  );
586 				} catch (Exception e) {
587 					e.printStackTrace();
588 				}
589 			}
590 		}
591 	}
592 
593 	private Method findMethod(String name) {
594 		int length = this.setters.size();
595 		for (int i = 0; i < length; i++) {
596 			Method method = (Method) this.setters.get(i);
597 			if (method.getName().equals(name)) {
598 				return method;
599 			}
600 		}
601 		return null;
602 	}
603 		
604 	private boolean isDataReady() {
605 		if (! checkSize()) {
606 			return false;
607 		}
608 		
609 		 // need at least PX, PY, PZ
610 		for (int i = 0; i < ESSENTIALS.length; i++) {
611 			if (this.common[ESSENTIALS[i]] == null) {
612 				return false;
613 			}
614 		}
615 		
616 		// check Glyph source dependent data.
617 		for (int i = 0; i < this.sourceEssentials.length; i++) {
618 			if (this.entryArray[this.sourceEssentials[i]] == null) {
619 				return false;
620 			}
621 		}
622 		return true;
623 	}
624 
625 	private boolean checkSize() {
626 		double[] x = (double[]) this.common[PX];
627 		double[] y = (double[]) this.common[PY];
628 		double[] z = (double[]) this.common[PZ];
629 		double[] scale = (double[]) this.common[SCALE];
630 		double[] xo = (double[]) this.common[OX];
631 		double[] yo = (double[]) this.common[OY];
632 		double[] zo = (double[]) this.common[OZ];
633 		double[] color = (double[]) this.common[COLOR];
634 		double[] trans = (double[]) this.common[ALPHA];
635 
636 		int size = this.entryNum;
637 
638 		if ((x != null && x.length != size) ||
639 			(y != null && y.length != size) ||
640 			(z != null && z.length != size) ||
641 			(scale != null && scale.length != size) ||
642 			(xo != null && xo.length != size) ||
643 			(yo != null && yo.length != size) ||			
644 			(zo != null && zo.length != size) ||
645 			(color != null && color.length != size) ||			
646 			(trans != null && trans.length != size) ||
647 			(this.userData != null && Array.getLength(this.userData) != size)
648 			) {
649 			return false;
650 		}
651 		for (int i = 0; i < this.entryArray.length; i++) {
652 			if (this.entryArray[i] != null &&
653 				Array.getLength(this.entryArray[i]) != size) {
654 				return false;
655 			}
656 		}
657 		return true;
658 	}
659 
660 	/***
661 	* After setting all necessary infomation, call this method to
662 	* construct GlyphModel.
663 	*/
664 	synchronized private void setSceneData() {
665 		if (isDataReady()) {
666 			setData();
667 		}
668 	}
669 
670 	private void setData() {
671 		synchronized (this.scenes) {
672 			boolean needModel = false;
673 			BranchGroup bg = getScene();
674 			if (bg == null) {
675 				needModel = true;
676 				if (DEBUG) {
677 					System.out.println("scene null.");
678 				}
679 			}
680 			
681 			if ((this.entryNum != this.oldEntryNum) || needModel) { // if entryNum has changed.
682 				/*
683 				 * make oldEntryNum and entryNum equal before modeling,
684 				 * so that other threads calling setData() do not model...
685 				 * Masahiro Takatsuka/2001-Oct-15
686 				 */
687 				this.oldEntryNum = this.entryNum;
688 				if (DEBUG) {
689 					System.out.println("modelling...");
690 				}
691 				reset();
692 				model();
693 			} else {
694 				if (DEBUG) {
695 					System.out.println("updating...");
696 				}
697 				update();
698 			}
699 		}
700 	}
701 
702 	/* ------------------------ SceneModeler ------------------------ */
703 	/***
704 	 * Computes a rotation matrix to align the src vector to dst vector.
705 	 */
706 	private Matrix3d rotationMatrixToAlignVector(Vector3d src,
707 												 Vector3d dst,
708 												 Matrix3d ra) {
709 		if (ra == null) {
710 			ra = new Matrix3d();
711 		}
712 
713 		double r1 = Math.sqrt(src.x * src.x + src.y * src.y + src.z * src.z);
714 		double r2 = Math.sqrt(dst.x * dst.x + dst.y * dst.y + dst.z * dst.z);
715 		double ay1 = Math.atan2(src.x, src.z);
716 		double ax1 = Math.acos(src.y / r1);
717 		double ay2 = Math.atan2(dst.x, dst.z);
718 		double ax2 = Math.acos(dst.y / r2);
719 
720 		if (DEBUG) {
721 			System.out.println("ax1, ay1 = " + ax1 + ", " + ay1);
722 			System.out.println("ax2, ay2 = " + ax2 + ", " + ay2);
723 		}
724 		this.mat1.rotY(ay1);
725 		this.mat2.rotX(ax1);
726 		this.matv1.mul(this.mat2, this.mat1);
727 
728 		this.mat1.rotX(-ax2);
729 		this.mat2.rotY(-ay2);
730 		ra.mul(this.mat2, this.mat1);
731 		ra.mul(this.matv1);
732 
733 		return ra;
734 	}
735 
736 	/*
737 	* 2do: set rotation components from orientation vector.
738 	* Masahiro Takatsuka/2001-Jul-06
739 	*/
740 	private void setTransform3D(int index, Transform3D t3d) {
741 		// translateion
742 		double x = this.common[PX][index];
743 		double y = this.common[PY][index];
744 		double z = this.common[PZ][index];
745 		this.trans.set(x, y, z);
746 
747 		// scale
748 		double scale;
749 		if (this.common[SCALE] != null) {
750 			scale = this.common[SCALE][index];
751 		} else {
752 			scale = 1.0;
753 		}
754 		scale *= this.defaultScale;
755 
756 		// set rotation
757 		if (this.common[OX] != null &&
758 			this.common[OY] != null &&
759 			this.common[OZ] != null) {
760 			x = this.common[OX][index];
761 			y = this.common[OY][index];
762 			z = this.common[OZ][index];
763 			this.dstVector.set(x, y, z);
764 			rotationMatrixToAlignVector(this.yAxis, this.dstVector, this.rot);
765 			t3d.set(this.rot, this.trans, scale);
766 		} else {
767 			t3d.set(scale, this.trans);
768 		}
769 	}
770 
771 	private void setDataToSource(int index) {
772 		int length = this.setters.size();
773 		if (this.converters == null || this.converters.length != length) {
774 			this.converters = new DataConverter[length];
775 			this.argTypeStrs = new String[length];
776 		}
777 
778 		for (int i = 0; i < length; i++) {
779 			Object array = this.entryArray[i];
780 			if (array == null) {
781 				continue;
782 			}
783 			Object arg = java.lang.reflect.Array.get(array, index);
784 			Method method = (Method) this.setters.get(i);
785 			Class[] argTypes = method.getParameterTypes();
786 			Class argType = argTypes[0];
787 			if (argType.isPrimitive()) {
788 				argType = ClassUtil.getWrapperClass(argType);
789 			}
790 			// check the argument types.
791 			if (this.converters[i] == null) {
792 				Class paramType = arg.getClass();
793 				this.converters[i] = DataConverterManager.findConverter(paramType, argType);
794 				if (DEBUG) {
795 					System.out.println("converter = " + this.converters[i]);
796 				}
797 				this.argTypeStrs[i] = argType.getName();
798 			}
799 			try {
800 				Object[] args = {this.converters[i].convert(arg, this.argTypeStrs[i])};
801 				if (DEBUG) {
802 					System.out.println("method = " + method + ", arg = " + args[0]);
803 				}
804 				ClassUtil.makeObjectPerform(this.source,
805 											  method.getName(),
806 											  args,
807 											  argTypes
808 											  );
809 			} catch (Exception e) {
810 				e.printStackTrace();
811 			}
812 		}
813 	}
814 
815 	private Node getNodeFromSource(int index) {
816 		Node node = this.source.getNode();
817 		if (node instanceof Shape3D) {
818 			Shape3D shape3d = (Shape3D) node;
819 			shape3d.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
820 			shape3d.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
821 			shape3d.setCapability(Shape3D.ALLOW_COLLISION_BOUNDS_READ);
822 			shape3d.setCapability(Shape3D.ALLOW_COLLISION_BOUNDS_WRITE);
823 			shape3d.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
824 			shape3d.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE);
825 			shape3d.setCapability(Node.ALLOW_BOUNDS_READ);
826 			shape3d.setCapability(Node.ALLOW_BOUNDS_WRITE);
827 			shape3d.setCapability(Node.ALLOW_AUTO_COMPUTE_BOUNDS_READ);
828 			shape3d.setCapability(Node.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE);
829 		}
830 
831 		return node;
832 	}
833 	
834 	private Node updateNode(Node node) {
835 		return this.source.updateNode(node);
836 	}
837 
838 	
839 	private ColoringAttributes setColoringAttributes(int index, ColoringAttributes ca) {
840 		if (ca == null) {
841 			ca = new ColoringAttributes();
842 		}
843 		try {
844 			ca.setCapability(ColoringAttributes.ALLOW_COLOR_READ);
845 			ca.setCapability(ColoringAttributes.ALLOW_COLOR_WRITE);			
846 			ca.setCapability(ColoringAttributes.ALLOW_SHADE_MODEL_READ);
847 			ca.setCapability(ColoringAttributes.ALLOW_SHADE_MODEL_WRITE);
848 		} catch (Exception e) {
849 			// NOP.
850 		}
851 		if (this.common[COLOR] != null) {
852 			double[] newColor = this.colorLT.mapValue(this.common[COLOR][index]);
853 			ca.setColor((float) newColor[0],
854 						(float) newColor[1],
855 						(float) newColor[2]);
856 			ca.setShadeModel(this.shadeModel);
857 		} else {
858 			float[] newColor = this.defaultColor.getRGBColorComponents(null);
859 			ca.setColor(newColor[0], newColor[1], newColor[2]);
860 			ca.setShadeModel(this.shadeModel);
861 		}
862 
863 		return ca;
864 	}
865 
866 	private TransparencyAttributes setTransparencyAttributes(int index, TransparencyAttributes ta) {
867 		if (ta == null) {
868 			ta = new TransparencyAttributes();
869 		}
870 		try {
871 			ta.setCapability(TransparencyAttributes.ALLOW_BLEND_FUNCTION_READ);
872 			ta.setCapability(TransparencyAttributes.ALLOW_BLEND_FUNCTION_WRITE);			
873 			ta.setCapability(TransparencyAttributes.ALLOW_MODE_READ);
874 			ta.setCapability(TransparencyAttributes.ALLOW_MODE_WRITE);
875 			ta.setCapability(TransparencyAttributes.ALLOW_VALUE_READ);
876 			ta.setCapability(TransparencyAttributes.ALLOW_VALUE_WRITE);
877 		} catch (Exception e) {
878 			// NOP.
879 		}
880 		if (this.common[ALPHA] != null) {
881 			double alpha = this.common[ALPHA][index];
882 			ta.setTransparency((float) alpha);
883 			ta.setTransparencyMode(this.transparencyMode);
884 		}
885 
886 		return ta;
887 	}
888 	
889 	private Material setMaterial(int index, Material mat) {
890 		if (mat == null) {
891 			mat = new Material();
892 		}
893 		try {
894 			mat.setCapability(Material.ALLOW_COMPONENT_READ);
895 			mat.setCapability(Material.ALLOW_COMPONENT_WRITE);			
896 		} catch (Exception e) {
897 			// NOP.
898 		}
899 
900 		// set only Diffuse color.
901 		double color;
902 		if (this.common[COLOR] != null) {
903 			color = this.common[COLOR][index];
904 			double[] newColor = this.colorLT.mapValue(color);
905 			colorTmp.set((float) newColor[0],
906 						 (float) newColor[1],
907 						 (float) newColor[2]);
908 			mat.setDiffuseColor(colorTmp);
909 		} else {
910 			float[] newColor = this.defaultColor.getRGBColorComponents(null);
911 			colorTmp.set(newColor[0], newColor[1], newColor[2]);
912 			mat.setDiffuseColor(colorTmp);			
913 		}
914 		
915 		// set lightingEnable flag.
916 		mat.setLightingEnable(this.lightingEnable);
917 
918 		return mat;
919 	}
920 	
921 	private Appearance setAppearance(int index, Appearance ap) {
922 		ap = (ap == null) ? new Appearance() : ap;
923 		try {
924 			ap.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_READ);
925 			ap.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE);
926 			ap.setCapability(Appearance.ALLOW_MATERIAL_READ);
927 			ap.setCapability(Appearance.ALLOW_MATERIAL_WRITE);
928 			ap.setCapability(Appearance.ALLOW_TEXTURE_READ);
929 			ap.setCapability(Appearance.ALLOW_TEXTURE_WRITE);
930 			ap.setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_READ);
931 			ap.setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE);
932 		} catch (Exception e) {
933 			//e.printStackTrace();
934 			// NOP skip..they're already set.
935 		}
936 		
937 		// set color.
938 		ColoringAttributes ca = ap.getColoringAttributes();
939 		ca = setColoringAttributes(index, ca);
940 		if (ap.getColoringAttributes() == null) {
941 			ap.setColoringAttributes(ca);
942 		}
943 		
944 		// set Material
945 		Material mat = ap.getMaterial();
946 		mat = setMaterial(index, mat);
947 		if (ap.getMaterial() == null) {
948 			ap.setMaterial(mat);
949 		}
950 		
951 		// set transparency.
952 		TransparencyAttributes ta = ap.getTransparencyAttributes();
953 		ta = setTransparencyAttributes(index, ta);
954 		if (ap.getTransparencyAttributes() == null) {
955 			ap.setTransparencyAttributes(ta);
956 		}
957 		
958 		return ap;
959 	}
960 
961   	/***
962 	 */
963   	protected void modelScene() {
964 		double x, y, z, scale;
965 		for (int i = 0; i < this.entryNum; i++) {
966 			// set entryArray to source
967 			setDataToSource(i);
968 
969 			// get shape3d.
970 			this.nodes[i] = getNodeFromSource(i);
971 
972 			// set UserData to Shape3D object.
973 			if (this.userData != null) {
974 				this.nodes[i].setUserData(Array.get(this.userData, i));
975 			}
976 
977 			// if Shape3D has
978 			Appearance ap = this.source.getAppearanceOfNode(this.nodes[i]);
979 			
980 			// create appearance
981 			ap = setAppearance(i, ap);
982 			
983 			// add appearance to Shape3D
984 			this.source.setAppearanceOfNode(this.nodes[i], ap);
985 			
986 			// create transform3d from this.common		
987 			setTransform3D(i, this.t3d);
988 			
989 			// create TransformGroup.
990 			this.tGroups[i] = new net.jbeans.j3d.transform.TransformGroup(this.t3d);
991 			
992 			// add Shape3D to TransformGroup
993 			this.tGroups[i].addChild(this.nodes[i]);
994 
995 			this.topBranch.addChild(this.tGroups[i]);
996 		}
997 		setScene(this.topBranch);
998 	}
999 	
1000   	/***
1001   	 *
1002   	 */
1003 	protected void updateScene() {
1004 		for (int i = 0; i < this.entryNum; i++) {
1005 			// get Transform3D
1006 			this.tGroups[i].getTransform(this.t3d);
1007 
1008 			// compute Transform3D
1009 			setTransform3D(i, this.t3d);
1010 
1011 			// set Transoform3D
1012 			this.tGroups[i].setTransform(this.t3d);
1013 
1014 			// set entryArray to source
1015 			setDataToSource(i);
1016 
1017 			// update shape3d
1018 			updateNode(this.nodes[i]);
1019 
1020 			// set UserData to Shape3D object.
1021 			if (this.userData != null) {
1022 				this.nodes[i].setUserData(Array.get(this.userData, i));
1023 			}
1024 
1025 			// get appearance
1026 			Appearance ap = this.source.getAppearanceOfNode(this.nodes[i]);
1027 			
1028 			// create appearance
1029 			ap = setAppearance(i, ap);
1030 			
1031 			// add appearance to Shape3D
1032 			this.source.setAppearanceOfNode(this.nodes[i], ap);
1033 		}
1034 	}
1035 }