/* This file is part of the source code for 3D-XplorMath-J, Version 1.0 (January 2008).
* Copyright (c) 2008 The 3D-XplorMath Consortium (http://3d-xplormath.org).
* This source code is released under a BSD License, which allows redistribution
* in source and binary form, with or without modification, provided copyright
* and license information are included, and with no warranty or guarantee of
* any kind. For details, see http://3d-xplormath.org/j/source/BSDLicense.txt
*/
package vmm.core3D;
import java.awt.Graphics2D;
import java.util.ArrayList;
import vmm.core.Exhibit;
import vmm.core.Transform;
import vmm.core.VMMSave;
import vmm.core.View;
/**
* An exhibit that can be rendered in 3D can be defined as a subclass of this class. It is not
* an absolute requirement that a 3D exhibit be a subclass of this class, since an Exhibit is always
* in charge of rendering itself. However, this class does provide some convenient default behavior
* for 3D exhibits. Remember that it is possible for a single exhibit to have both 2D and 3D views.
*/
abstract public class Exhibit3D extends Exhibit {
/**
* When the {@link #computeDrawDataHook(View, Transform)} method is called with a 3D View and Transform, the
* Transform3D that is being used is recorded here so that it can be compared with the Transform3D that is
* used the next time the method is called. This is only for use in rare circumstances when am Exhibit has
* cached data that depends on the transform.
*/
protected Transform3D previousTransform3D;
/**
* The value of this variable is returned by the {@link #getDefaultViewpoint()} method. When the Exhibit
* is installed in a View3D, this vector is used as the initial viewpoint for viewing the exhibit.
*/
@VMMSave protected Vector3D defaultViewpoint = new Vector3D(20,0,0);
/**
* The value of this variable is returned by the {@link #getDefaultViewUp()} method. When the Exhibit
* is installed in a View3D, this vector is used as the initial view up vector. A null value indicates
* that the default should be used.
*/
@VMMSave protected Vector3D defaultViewUp = null;
/**
* Returns the default transform for use in the specified View. If the View is an instance of the {@link View3D}
* class, then a {@link Transform3D} object is returned; this object is constructed from the
* exhibit's default viewpoint and default window. If the view is not a View3D, then a 2D {@link Transform} is
* returned that is constructed using the exhibit's default window only.
* @see #setDefaultViewpoint(Vector3D)
* @see Exhibit#setDefaultWindow(double, double, double, double)
*/
public Transform getDefaultTransform(View view) {
double[] window = getDefaultWindow();
if (view instanceof View3D) {
Transform3D tr = new Transform3D(defaultViewpoint, window[0], window[1], window[2], window[3]);
if (defaultViewUp != null)
tr.setImagePlaneYDirection(defaultViewUp);
return tr;
}
else
return new Transform(window[0], window[1], window[2], window[3]);
}
/**
* Returns the default View of this Exhibit. In the Exhibit3D class, the return value is a basic {@link View3D}.
*/
public View getDefaultView() {
return new View3D();
}
/**
* Returns the default viewpoint for viewing this Exhibit in 3D.
* @see #setDefaultViewpoint(Vector3D)
*/
public Vector3D getDefaultViewpoint() {
return defaultViewpoint;
}
/**
* Set the default viewpoint for viewing this exhibit in 3D. The default viewpoint is used
* to construct the default 3D view of this Exhibit in {@link #getDefaultTransform(View)}.
* Subclasses of Exhibit3D can call this method -- probably in a construtor -- to set a resonable viewpoint
* for the particular exhibit. If the default viewpoint is set to null, then the default
* of the {@link Transform3D} class is used; this default is the point (20,0,0).
* @param defaultViewpoint the default viewpoint for this Exhibit3D, or null to indicate that the
* default viewpoint in Transform3D is to be used.
*/
public void setDefaultViewpoint(Vector3D defaultViewpoint) {
this.defaultViewpoint = defaultViewpoint == null ? new Vector3D(20,0,0) : defaultViewpoint;
}
/**
* Returns the default view up for viewing this Exhibit in 3D.
* @see #setDefaultViewUp(Vector3D)
*/
public Vector3D getDefaultViewUp() {
return defaultViewpoint;
}
/**
* Set the default view up vector for viewing this exhibit in 3D. The value of this vector
* is used to set the view up vector when the exhibit is installed. The initial value is null,
* which indicates that the default view up should be accepeted.
* @param defaultViewUp the default view up vector for this Exhibit3D, or null to indicate that the
* default view up should be accepted.
*/
public void setDefaultViewUp(Vector3D defaultViewUp) {
this.defaultViewUp = defaultViewUp;
}
/**
* Called by {@link Exhibit#render(Graphics2D, View, Transform, ArrayList)} to give the exhibit a chance
* to compute its cached data, if necessary. This method is not meant to be called directly. It exists
* only to make it possible to write a unified render method that will work for both the
* basic Exhibit class and for its subclasses. The method in this Exhibit3D class simply calls either
* {@link Exhibit#computeDrawData(View, boolean, Transform, Transform)} or
* {@link Exhibit3D#computeDrawData3D(View3D, boolean, Transform3D, Transform3D)}, depending on
* whether the View is a 2D or 3D View.
*
Subclasses should almost always override computeDrawData and/or
* computeDrawData3D instead of overriding this method.
*/
protected void computeDrawDataHook(View view, Transform transform) {
if (view instanceof View3D && transform instanceof Transform3D) {
computeDrawData3D((View3D)view, exhibitNeedsRedraw, previousTransform3D, (Transform3D)transform);
previousTransform3D = (Transform3D)(transform.clone());
}
else {
computeDrawData(view, exhibitNeedsRedraw, previousTransform, transform);
previousTransform = (Transform)(transform.clone());
}
}
/**
* Called by {@link Exhibit#doDraw(Graphics2D, View, Transform)} when the exhibit needs to
* redraw itself. This method is not meant to be called directly. It exists
* only to make it possible to write a unified doDraw method that will work for both the
* basic Exhibit class and for its subclasses. The method in this Exhibit3D class simply calls either
* {@link Exhibit#doDraw(Graphics2D, View, Transform)} or
* {@link Exhibit3D#doDraw3D(Graphics2D, View3D, Transform3D)}, depending on
* whether the View is a 2D or 3D View.
*
Subclasses should almost always override doDraw and/or
* doDraw3D instead of overriding this method.
*/
protected void doDrawHook(Graphics2D g, View view, Transform transform) {
if (view instanceof View3D && transform instanceof Transform3D)
doDraw3D(g,(View3D)view,(Transform3D)transform);
else
doDraw(g,view,transform);
}
/**
* Recopmputes cached data, if necessary, for a 3D rendering of this exhibit.
* The method in the Exhibit3D class does nothing. Subclasses should override this method as appropriate.
* Note that this method is called only if the Exhibit is being rendered in a View3D. Exhibits that have
* both two and three dimensional renderings can also override {@link Exhibit#computeDrawData(View, boolean, Transform, Transform)}
* to say what should be drawn in a 2D view.
* @param view the 3D View where the Exhibit is about to be drawn.
* @param exhibitNeedsRedraw if true, then something about the Exhibit has changed that probably requires
* recomputation of cached data. For example, this is set to true when one of the Parameters of the Exhibit
* has changed since the previous redraw.
* @param previousTransform3D the Transform3D that was used the last time this exhibit was drawn. This can be null, if
* this is the first time that the Exhibit is being drawn (in 3D).
* @param newTransform3D the transform that will be used to draw the Exhibit during the current drawing operation.
* This parameter and the previousTransform3D parameter are provided so that the Exhbit can detect those rare
* cases where cached data exists that depends on the transform. Most Exhibits will just ignore the
* transform parameters.
*/
protected void computeDrawData3D(View3D view, boolean exhibitNeedsRedraw, Transform3D previousTransform3D, Transform3D newTransform3D) {
}
/**
* Draws this Exhibit in a 3D view. The method in the Exhibit3D class does nothing. Subclasses should override
* this method to do the actual drawing. When this method is called, {@link #computeDrawData3D(View3D, boolean, Transform3D, Transform3D)}
* has already been called, so that any cached data should be correct.
* Note that this method is called only if the Exhibit is being drawn in a View3D. Exhibits that have
* both two and three dimensional renderings should also override {@link Exhibit#doDraw(Graphics2D, View, Transform)}.
*
When drawing a 3D exhibit, you are strongly advised to use the drawing routines supplied by the * {@link View3D} and {@link View3DLit} classes. These routines will automatically produce the correct results * in stereo views -- the same is not true about direct drawing to the graphics context. * @param g the graphics context where the exhibit is being drawn. * @param view The View3D in which the exhibit is being drawn. In general, it is advisable to use the view for * all drawing operations. * @param transform The transform that is being used to draw the exhibit. */ protected void doDraw3D(Graphics2D g, View3D view, Transform3D transform) { } }