/* Graphics (GR) domain director with synchronous/reactive semantics Copyright (c) 1998-2014 The Regents of the University of California. All rights reserved. Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, modify, and distribute this software and its documentation for any purpose, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. PT_COPYRIGHT_VERSION_2 COPYRIGHTENDKEY */ package ptolemy.domains.gr.kernel; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import ptolemy.actor.Actor; import ptolemy.actor.CompositeActor; import ptolemy.actor.Director; import ptolemy.actor.FiringEvent; import ptolemy.actor.IOPort; import ptolemy.actor.Receiver; import ptolemy.actor.TypedCompositeActor; import ptolemy.actor.sched.Schedule; import ptolemy.actor.sched.Scheduler; import ptolemy.actor.sched.StaticSchedulingDirector; import ptolemy.actor.util.Time; import ptolemy.data.IntToken; import ptolemy.data.expr.Parameter; import ptolemy.data.type.BaseType; import ptolemy.kernel.ComponentEntity; import ptolemy.kernel.CompositeEntity; import ptolemy.kernel.util.IllegalActionException; import ptolemy.kernel.util.InternalErrorException; import ptolemy.kernel.util.InvalidStateException; import ptolemy.kernel.util.NameDuplicationException; import ptolemy.kernel.util.Nameable; import ptolemy.kernel.util.NamedObj; import ptolemy.kernel.util.Workspace; /////////////////////////////////////////////////////////////////// //// GRDirector /** GR is a domain for displaying three-dimensional graphics in Ptolemy II. GR is an untimed domain in where actors are connected in an acyclic directed graph. Actors are fired according to a simple topological sort of the graph. Nodes in the graph that have no descendants are assumed to be consumers of data produced by the rest of the model.
The basic idea behind the GR domain is to arrange geometry and
transform actors in a directed acyclic graph to represent the location
and orientation of objects in a scene. This topology of connected GR
actors form what is commonly called a scene graph in computer graphics
literature. The GR director converts the GR scene graph into a Java3D
representation for rendering on the computer screen.
@see GRReceiver
@see GRActor
@author C. Fong, Steve Neuendorffer, Contributor: Christopher Hylands
@version $Id: GRDirector.java 70402 2014-10-23 00:52:20Z cxh $
@since Ptolemy II 1.0
@Pt.ProposedRating yellow (chf)
@Pt.AcceptedRating yellow (vogel)
*/
public class GRDirector extends StaticSchedulingDirector {
/** Construct a director in the default workspace with an empty string
* as its name. The director is added to the list of objects in
* the workspace. Increment the version number of the workspace.
* @exception NameDuplicationException If construction of Time objects fails.
* @exception IllegalActionException If construction of Time objects fails.
*/
public GRDirector() throws IllegalActionException, NameDuplicationException {
super();
_init();
}
/** Construct a director in the workspace with an empty name.
* The director is added to the list of objects in the workspace.
* Increment the version number of the workspace.
*
* @param workspace The workspace of this object.
* @exception NameDuplicationException If construction of Time objects fails.
* @exception IllegalActionException If construction of Time objects fails.
*/
public GRDirector(Workspace workspace) throws IllegalActionException,
NameDuplicationException {
super(workspace);
_init();
}
/** Construct a director in the given container with the given name.
* If the container argument is null, a NullPointerException will
* be thrown. If the name argument is null, then the name is set
* to the empty string. Increment the version number of the workspace.
*
* @param container Container of the director.
* @param name Name of this director.
* @exception IllegalActionException If the
* director is not compatible with the specified container.
* @exception NameDuplicationException If the container is not a
* CompositeActor and the name collides with an entity in the container.
*/
public GRDirector(CompositeEntity container, String name)
throws IllegalActionException, NameDuplicationException {
super(container, name);
_init();
}
///////////////////////////////////////////////////////////////////
//// parameters ////
/** A parameter representing the number of times that postfire()
* may be called before it returns false. If the value is less
* than or equal to zero, the execution will never return false
* in postfire(), and thus the execution continues indefinitely.
* This parameter must contain an IntToken.
* The default value is an IntToken with the value zero.
*/
public Parameter iterations;
/** A parameter that indicates the time lower bound of each
* iteration. This parameter is useful for guaranteeing that
* each frame of an animation takes at least a certain amount of
* time before proceeding to the next frame. This parameter is
* measured in milliseconds.
* This parameter must contain an IntToken.
* The default value is an IntToken with value the 33, which
* corresponds roughly to 30 frames per second.
*/
public Parameter iterationTimeLowerBound;
///////////////////////////////////////////////////////////////////
//// public methods ////
/** Clone the director into the specified workspace. This calls the
* base class and then copies the parameter of this director. The new
* actor will have the same parameter values as the old.
*
* @param workspace The workspace for the new object.
* @return A new object.
* @exception CloneNotSupportedException If one of the attributes
* cannot be cloned.
*/
@Override
public Object clone(Workspace workspace) throws CloneNotSupportedException {
_reset();
GRDirector newObject = (GRDirector) super.clone(workspace);
return newObject;
}
/** Override the super class method. This method does nothing and
* everything is postponed to the postfire() method. This assures
* that inputs are stable.
*/
@Override
public void fire() throws IllegalActionException {
// do nothing.
// Everything is postponed to the postfire() method.
}
/** Schedule a firing of the given actor at the given time.
* If there is an executive director, this method delegates to it.
* Otherwise, it sets its own notion of current time to that
* specified in the argument. The reason for this is to enable
* GRDirector to be a top-level director and to support the design pattern
* where a director requests a refiring at the next time it wishes
* to be awakened, just prior to returning from fire(). DEDirector,
* for example, does that, as does the SDFDirector if the period
* parameter is set.
* @param actor The actor scheduled to be fired.
* @param time The scheduled time.
* @param microstep The microstep.
* @return The time returned by the executive director, or
* or the specified time if there isn't one.
* @exception IllegalActionException If by the executive director.
*/
@Override
public Time fireAt(Actor actor, Time time, int microstep)
throws IllegalActionException {
// Note that the actor parameter is ignored, because it does not
// matter which actor requests firing.
Nameable container = getContainer();
if (isEmbedded() && container instanceof Actor) {
Actor modalModel = (Actor) container;
Director executiveDirector = modalModel.getExecutiveDirector();
if (executiveDirector != null) {
return executiveDirector.fireAt(modalModel, time);
}
}
setModelTime(time);
return time;
}
/** Return the current "time". The GR domain is not a timed domain,
* so this method is semantically meaningless. However, this method
* is implemented in order to get timed domains to work inside the
* GR domain. In particular, this method will give actors a "fake"
* impression of advancement of time.
*
* @return The current "time"
* @deprecated As of Ptolemy II 4.1, replaced by
* {@link #getModelTime()}
*/
@Deprecated
@Override
public double getCurrentTime() {
return getModelTime().getDoubleValue();
}
/** Return the current "time". The GR domain is not a timed domain,
* so this method is semantically meaningless. However, this method
* is implemented in order to get timed domains to work inside the
* GR domain. In particular, this method will give actors a "fake"
* impression of advancement of time.
*
* @return The current "time"
*/
@Override
public Time getModelTime() {
// FIXME: This is bogus... It violates the time semantics
// of Ptolemy II, where time coherence is guaranteed by the
// hierarchy. The top level advances time, not lower levels.
// The tree structure of a hierarchy ensures coherence.
// This hack only works if there is exactly one "inside director."
// See the Pendulum demo for a model that depends on this.
if (_pseudoTimeEnabled == true) {
return _insideDirector.getModelTime();
} else {
return super.getModelTime();
}
}
/** Return maximum value for type double. Since the GR domain is not a
* timed domain, so this method does not return any meaningful value.
* However, this method is implemented so that GR will work within
* timed domains.
*
* @return The maximum value for type double.
*/
@Override
public Time getModelNextIterationTime() {
// FIXME: This is bogus... It violates the time semantics
// of Ptolemy II, where time coherence is guaranteed by the
// hierarchy. The top level advances time, not lower levels.
// The tree structure of a hierarchy ensures coherence.
// This hack only works if there is exactly one "inside director."
// See the Pendulum demo for a model that depends on this.
try {
return new Time(this, Double.POSITIVE_INFINITY);
} catch (IllegalActionException e) {
// If the time resolution of the director is invalid,
// it should have been caught before this.
throw new InternalErrorException(e);
}
}
/** Initialize all the actors associated with this director. Perform
* some internal initialization for this director.
*
* @exception IllegalActionException If the initialize() method of
* one of the associated actors throws it.
*/
@Override
public void initialize() throws IllegalActionException {
super.initialize();
_disabledActors = new HashSet