Package syn3d.nodes

Source Code of syn3d.nodes.SceneNode

/* ========================
* JSynoptic : a free Synoptic editor
* ========================
*
* Project Info:  http://jsynoptic.sourceforge.net/index.html
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 2001-2004, by :
*     Corporate:
*         EADS Corporate Research Center
*     Individual:
*         Nicolas Brodu
*
* $Id: SceneNode.java,v 1.14 2006/11/23 15:50:31 ogor Exp $
*
* Changes
* -------
* 19-Mar-2004 : Creation date (NB);
*
*/
package syn3d.nodes;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.Icon;

import simtools.data.EndNotificationListener;
import simtools.util.ListenerManager;
import syn3d.base.ActiveNode;
import syn3d.base.PluginManager;

/**
*
*/
public class SceneNode extends GroupNode implements EndNotificationListener, Serializable {

  static final long serialVersionUID = 7783556837479668060L;
 
  /**
   * In rotation mode, the user rotates the whole scene and can zoom in or out.
   * Rotation mode is adapted to study one object. This is the default
   */
  public static final int ROTATION_MODE = 0;

  /**
   * In fly-by mode, the user can freely move in the scene. This is more adapted for
   * scenes with multiple objects or for objects with a complex internal geometry to study.
   */
  public static final int FLY_BY_MODE = 1;

  protected int viewingMode;// = FLY_BY_MODE;
 
 
  /**
   * @return Returns the viewingMode.
   */
  public int getViewingMode() {
    return viewingMode;
  }
 
  /**
   * @param viewingMode The viewingMode to set.
   */
  public void setViewingMode(int viewingMode) {
    this.viewingMode = viewingMode;
  }

 
  /**
   * Current file name used for saving the scene
   */
  protected String fileName = null;

  /** An array of UniverseChangeListener objects */
    protected transient ListenerManager listeners = new ListenerManager();
   
    /**
     * An array of Dirty nodes to update before calling listeners
     * The dirty nodes are then automatically removed from this array, as they're supposed to be cleaned up
     */
    protected transient ListenerManager dirtyNodes = new ListenerManager(); // Use ListenerManager too

    protected static int anonymousSceneNumber = 0;
   
  
   
  /**
   * This timer is used to gather notify events and send them at a reasonable rate to 3D motors.
   */
  protected transient Timer timer;
 
 
  /**
   * True when the user has changed the period for refreshing the scene>
   */
  protected boolean refreshPeriodChanged = false;
 
  static public int REFRESH_PERIOD = 100;
 
  protected long refreshPeriod = REFRESH_PERIOD;
   
 
  public SceneNode(ActiveNode parent) {
        super(parent);
        if (!(parent instanceof RootNode)) return;
        anonymousSceneNumber++;
        name = NodeResourcesManager.getNodeName("Scene") + ((anonymousSceneNumber == 1) ? "" : String.valueOf(anonymousSceneNumber));
    }
   
  /**
   * Restore scene : subclasses can restore the scene once all ActiveNOde have been initialised
   */
  public void restoreScene(PluginManager pm){
  }
   
    /**
     * Use this function to get the scene containing this node
     * @param node A node whose scene is unknown
     * @return the scene in which this node resides, or null if this node is not attached to a scene
     */
    public static SceneNode getScene(ActiveNode node) {
        while (node != null) {
            if (node instanceof SceneNode) return (SceneNode)node;
            node = node.getParent();
        }
        return null;
    }
   
    /* (non-Javadoc)
     * @see syn3d.base.ActiveNode#getActions()
     */
    public List getActions() {
        ArrayList list = new ArrayList();
        if (isVisible())
            list.add(NodeResourcesManager.getResources().getString("Close"));
        else
            list.add(NodeResourcesManager.getResources().getString("Show"));

    if (getViewingMode()== SceneNode.ROTATION_MODE) {
      list.add("Fly-by viewing mode");
    } else
      list.add("Rotation viewing mode");

        //list.add(NodeResourcesManager.getResources().getString("Properties"));
   
    return list;
    }

    /* (non-Javadoc)
     * @see syn3d.base.ActiveNode#doAction(java.lang.String)
     */
    public void doAction(Object action) {
        if (action==null) return;
        if (action.equals(NodeResourcesManager.getResources().getString("Close"))) {
            setVisible(false);
        }
        if (action.equals(NodeResourcesManager.getResources().getString("Show"))) {
            setVisible(true);
        }
    if (action.equals("Fly-by viewing mode")) {
      setViewingMode(SceneNode.FLY_BY_MODE);
    }
    if (action.equals("Rotation viewing mode")) {
      setViewingMode(SceneNode.ROTATION_MODE);
    }
        if (action.equals(NodeResourcesManager.getResources().getString("Properties"))) {
          // TODO : light properties, (ambient light and directional)
          // TODO add lights
        }
    }

    public boolean isVisible() {
        return false;
    }

    public void setVisible(boolean status) {
        // For subclasses
    }
   
   
    public void setRefreshPeriod(long period){
      if ((period!=refreshPeriod) && (period>0)){
        refreshPeriodChanged = true;
        refreshPeriod = period;
      }
    }
    public long getRefreshPeriod(){
      return refreshPeriod;
    }
   
    protected static Icon icon = NodeResourcesManager.resources.getIcon("sceneIcon");
    public Icon getIcon() {
        return icon;
    }

    public void restoreReferences(ActiveNode parent) {
        super.restoreReferences(parent);
        if (!(parent instanceof RootNode)) return;
     }

    public boolean saveChildren() {
        return super.saveChildren();
    }


    /**
     * Register the scene as the unique listener for data events in the whole scene graph.
     * This way, all events coming from the same source are fusionned into a single event
     * for the scene
     */
    public void notificationEnd(Object referer) {
      notifyChange();
    }

    /**
     * Notify listeners that this scene has changed.
     * For performance purposes, all notification changes are coalesced into a single event
     * no more than the scene period notification delay.
     * @see simtools.data.EndNotificationListener#notificationEnd(java.lang.Object)
     */
   
  protected class SceneTimerTask extends TimerTask{
    public void run() {
      synchronized(SceneNode.this) {
        notifyListeners();
      }
    }
  }
  protected synchronized void notifyChange() {
     // if there is a timer and no change about the refreshperiod, let it do its job
   
    if (refreshPeriodChanged || timer == null){
      refreshPeriodChanged = false;
      if (timer!=null)
        timer.cancel();
      timer = new Timer(true); // do not block the application on exit
      timer.schedule(new SceneTimerTask(),0,refreshPeriod);
    }
  }


    /**
     * Removes this node from the parent list. Notifies the parents for structural change.
     */
    public void remove() {
      super.remove();
  
      if (timer!=null)
      timer.cancel();
    }
   
  // Listeners related functions. Take care of duplicates

  public void addListener(SceneChangeListener dsl) {
    listeners.add(dsl);
  }

  public void removeListener(SceneChangeListener dsl) {
    listeners.remove(dsl);
  }

  // Dirty Nodes handling. Idem

  public void addDirtyNode(DirtyNode node) {
    dirtyNodes.add(node);
  }

  public void removeDirtyNode(DirtyNode node) {
    dirtyNodes.remove(node);
  }

  /** Call this when the scene changed, to notify all registered listeners */
  public void notifyListeners() {
      // Do not even bother to cleanup dirty nodes if there is noone to see the changes
   
    if (listeners.size() == 0) return;
      if (dirtyNodes.size()>0) {
        synchronized(dirtyNodes) {
          int n = dirtyNodes.size(); // only one call outside loop
          for (int i=0; i<n; ++i) {
              DirtyNode dn = (DirtyNode)dirtyNodes.get(i);
              if (dn!=null) dn.cleanup();
          }
        // Nodes are clean now.
        dirtyNodes.clear();
        }
      }
      synchronized(listeners) {
        int n = listeners.size(); // only one call outside loop
        for (int i=0; i<n; ++i) {
            SceneChangeListener ucl = (SceneChangeListener)listeners.get(i);
            if (ucl!=null) ucl.sceneChanged(this);
        }
      }
  }

  /**
   * Receive change notification events for objects in this scene and propagate them
   * to this scene listeners.
   * Don't propagate the event to the root node, as it doesn't care for it.
   */
    protected void propagateInternalChangeEvent(ActiveNode node) {
        notifyListeners();
    }

    /**
     * Catch highlight events as this can cause repaint.
     * This is just a hook so the Root can notify its own listeners
     */
    protected void propagateHighlightEvent(ActiveNode node, boolean on) {
        notifyListeners();
        super.propagateHighlightEvent(node,on);
    }

   
   
   
    /**
     * Initialize 2D rotation algorithm with the current position as origin.
     * Typically, this is related to mouse positions in X and Y.
     */
    public void init2DPosition(int posX, int posY) {
    }
   
    /**
     * Does a rotation of the scene according to moves in a 2D coordinate system.
     * Use init2DPosition to position an origin, then do as many rotate2D as required. 
     * @param newX The new X position in 2D, typically a mouse position
     * @param newY The new Y position in 2D, typically a mouse position
     */
    public void rotate2D(int newX, int newY) {
    }

    /**
     * Does a translation of the scene according to moves in a 2D coordinate system.
     * Use init2DPosition to position an origin, then do as many translate2D as required. 
     * @param newX The new X position in 2D, typically a mouse position
     * @param newY The new Y position in 2D, typically a mouse position
     */
    public void translate2D(int newX, int newY) {
    }
   
    /**
     * Uses the 2D increments in position to compute a zoom factor, then zooms the scene accordingly.
     * @param newX The new X position in 2D, typically a mouse position
     * @param newY The new Y position in 2D, typically a mouse position
     */
    public void zoom2D(int newX, int newY) {
    }

    /**
     * Zooms in or out of the scene according to the increment. This is an arbitrary algorithm
     * to help create correct zoom factors. You could use setZoomFactor and then update
     * the zoom matrix directly, with the same effect.<br>
     * The added value of this function is to provide a relative and easy to manipulate
     * way to zoom in or out, with increments like +1 or -1 for small zooms, and +10 and -10
     * for greater zooms, etc...<br>
     * @param zoomIncrement A value typically 1 or -1, but which can be greater for fast zooms.
     * Positive values zoom in, negative values zoom out.
     */
    public void zoom(int zoomIncrement) {
    }
   
    /**
     * Turns perspective on an off
     */
    public void changeProjection() {
    }

    /** Reset all values to default */
    public void reset() {
    }

    /** Auto zooms the scene out of all objects */
    public void autoZoom() {
    }

    /**
     * Adds or removes a single pick at the given position to the selected objects.
     * @param posX the 2D X position where to do the picking  
     * @param posY the 2D Y position where to do the picking
     * @return Returns the current selection, possibly an empy array
     * @see ActiveNode.higlight(boolean,Object) 
     */
    public ArrayList toggleSinglePick(int posX, int posY) {
      return new ArrayList();
    }

    /**
     * Adds or removes all picks between the given position and the last position,
     * to the selected objects.
     * @param posX the 2D X position defining a region with the last position. All objects in this region should be picked.    
     * @param posX the 2D Y position defining a region with the last position. All objects in this region should be picked.    
     * @return Returns the current selection, possibly an empy array 
     * @see ActiveNode.higlight(boolean,Object) 
     */
    public ArrayList toggleAllPicks(int posX, int posY) {
      return new ArrayList();
    }

    /**
     * Selects a single pick at the given position.
     * @param posX the 2D X position where to do the picking  
     * @param posY the 2D Y position where to do the picking  
     * @return Returns the picked node or possibly a null object if there was nothing to pick at this position 
     * @see ActiveNode.higlight(boolean,Object) 
     */
    public ActiveNode pick(int posX, int posY) {
      return null;
    }

    private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
    out.defaultWriteObject();
  }

    private void readObject(java.io.ObjectInputStream in) throws java.lang.ClassNotFoundException, java.io.IOException {
      in.defaultReadObject();
      listeners = new ListenerManager();
      dirtyNodes = new ListenerManager();
    }
}
TOP

Related Classes of syn3d.nodes.SceneNode

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.