Package net.sf.mrailsim.trains

Source Code of net.sf.mrailsim.trains.Train

/************************************************************************************

    MRailSim - a model railway simulation program - http://mrailsim.sourceforge.net/
    Copyright (C) 2004,2007  Bernd Arnold

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

   
************************************************************************************/


package net.sf.mrailsim.trains;

import java.awt.Graphics;
import java.util.ArrayList;

import net.sf.mrailsim.rails.Node;
import net.sf.mrailsim.rails.Track;
import net.sf.mrailsim.rails.TrackPosition;
import net.sf.mrailsim.shared.Logger;
import net.sf.mrailsim.signals.MainSignal;
import net.sf.mrailsim.signals.PreSignal;

public class Train {

  /**
   * The unique id of this train
   */
  private final long id;
 
  /**
   * The head and the tail of this train are ported to the TrainTermination class.
   * @see TrainTermination
   */
  private final TrainTermination head;
  private final TrainTermination tail;
 
  /**
   * Length of this train
   */
  private final int length;
 
  /**
   * How far this train has traveled since last reset to 0. It is
   * increased each time this train is moved.
   */
  // TODO: what if an overflow occurs?
  private long distanceTravelled = 0;
 
  /**
   * Reference to the train group this train belongs to. Is <code>null</code>,
   * if this train is not a member of any train group.
   * @see TrainGroup
   */
  private TrainGroup trainGroup;
 
  /**
   * A list of tracks this train resides. It is updated each time the
   * train terminations change the track.
   */
  private ArrayList<Track> tracksOccupied;
 
  private DrivingControl drivingControl;

 
  /**
   * Class constructor; initializes this train.
   * @param id      the unique id of this train
   * @param length  the length of this train
   */
  public Train( long id, int length ) {
    this.id = id;
    this.length = length;
   
    head = new TrainTermination( this );
    tail = new TrainTermination( this );

    tracksOccupied = new ArrayList<Track>();
  }
 
  // TODO: Fill class

  /**
   * Returns the id of this train.
   * @return  the train id
   */
  public long getId() {
    return id;
  }

  /**
   * Returns the train group this train is a member of.
   * @return  the train group or <code>null</none>, if none assigned
   */
  public TrainGroup getTrainGroup() {
    return trainGroup;
  }

  /**
   * Sets a new train group this train is a member of. Sets also the field
   * drivingControl to the train group's driving control.
   *
   * @param trainGroup  the train group this train is a member of
   * @see #drivingControl
   * @see DrivingControl
   */
  public void setTrainGroup( TrainGroup trainGroup ) {
    this.trainGroup = trainGroup;
    drivingControl = trainGroup.getDrivingControl();
  }

  /**
   * Returns the length of this train.
   * @return  the length of this train
   */
  public int getLength() {
    return length;
  }

  /**
   * Returns the train termination that is responsible for the head of this train.
   * @return  the train termination for the head
   */
  public TrainTermination getHead() {
    return head;
  }

  /**
   * Returns the train termination that is responsible for the tail of this train.
   * @return  the train termination for the tail
   */
  public TrainTermination getTail() {
    return tail;
  }

  /**
   * Moves the train the given amount. Depending on the driving direction this
   * method moves the train forward or backward.
   * @param distance  the distance the train should be moved, must be greater
   *                  or equal 0
   */
  void move( int distance ) {
    if ( distance <= 0 ) {
      return;
    }
   
    try {
      if ( getDirection() == DrivingControl.Direction.FORWARD ) {
        head.moveAhead( distance );
        tail.moveBack( distance );
        distanceTravelled += distance;
      } else if ( getDirection() == DrivingControl.Direction.BACKWARD ) {
        tail.moveAhead( distance );
        head.moveBack( distance );
        distanceTravelled += distance;
      }
    } catch (Exception e) {
      e.printStackTrace();
      System.exit(2);
    }
  }

  public void setPositions( TrackPosition trackPositionHead, TrackPosition trackPositionTail ) {
    tracksOccupied.add( trackPositionHead.getTrack() );
    // TODO: if different track, also add!
//    tracksOccupied.add( trackPositionTail.getTrack() );
    head.setPosition( trackPositionHead );
    tail.setPosition( trackPositionTail );
  }

  /**
   * Returns the distance this train has already traveled.
   * @return  the distance
   */
  public long getDistanceTravelled() {
    return distanceTravelled;
  }
 
  /**
   * Returns the direction in which this train will go when moved. Since
   * the direction is not controlled by an individual train, the driving control
   * is questioned for the direction.
   * @return  the direction this train will travel
   * @see  DrivingControl.Direction
   */
  public DrivingControl.Direction getDirection() {
    return drivingControl.getDirection();
  }
 
  /**
   * Is called to inform this train that the track has changed by a train termination.
   * So either a new track was entered or an already entered track was left now.
   * This train informs the new or old track that the train has entered or left.
   * @param termination  the reporting train termination, <code>head</code> or <code>tail</code>
   * @param oldTrack  the old track the termination was on
   * @param newTrack  the new track the termination is on now
   * @param node  the involved node
   * @see  TrainTermination
   */
  void trackChanged( TrainTermination termination, Track oldTrack, Track newTrack, Node node ) {
    if ( getDirection() == DrivingControl.Direction.FORWARD ) {
      if ( termination == head ) {
        tracksOccupied.add( newTrack );
        newTrack.trainEnters( this, node );
        newTrackEntered( newTrack, node );
      }
      if ( termination == tail ) {
        tracksOccupied.remove( oldTrack );
        oldTrack.trainLeaves( this );
      }
    }
    if ( getDirection() == DrivingControl.Direction.BACKWARD ) {
      if ( termination == head ) {
        tracksOccupied.remove( oldTrack );
        oldTrack.trainLeaves( this );
      }
      if ( termination == tail ) {
        tracksOccupied.add( newTrack );
        newTrack.trainEnters( this, node );
        newTrackEntered( newTrack, node );
      }
    }
   
    //TODO: inform traingroup, too
    //TODO: Really necessary?
  }

  private void newTrackEntered( Track newTrack, Node node ) {
    // TODO Look more tracks ahead!
    Track nextTrack = null;
    Node nextNode = null;
    try {
      nextNode = newTrack.getOutgoingNode( node );
      nextTrack = nextNode.getOtherTrack( newTrack );
    } catch (Exception e) {
      // TODO Handle right
      e.printStackTrace();
      System.exit( 2 );
    }
   
    if ( nextTrack == null ) {
      // TODO: Handle better
      System.err.println( "nextTrack is null in newTrackEntered(...), train #" + id + " track #" + newTrack.getId() + "." );
      System.exit( 2 );
    }
   
    if ( nextNode == null ) {
      // TODO: Handle better
      System.err.println( "nextNode is null in newTrackEntered(...), train #" + id + " track #" + newTrack.getId() + "." );
      System.exit( 2 );
    }
   
    // TODO: Only check for signals when train is the first one in train group or the last one!
    // TODO: move code to method checkForSignalsInSight(...) ?
    for ( PreSignal signal : nextTrack.getPreSignals() ) {
      if ( signal.isBoundToNode( nextNode ) ) {
        Logger.log( Logger.Component.TRAIN, Logger.Level.INFORMATION, "Train #" + id + " sees pre signal #" +
            signal.getId() + " showing " + signal.getDisplay() + "." );
        drivingControl.preSignalAhead( signal.getDisplay(), signal.getDistanceToMainSignal() );
      }
    }

    for ( MainSignal signal : nextTrack.getMainSignals() ) {
      if ( signal.isBoundToNode( nextNode ) ) {
        Logger.log( Logger.Component.TRAIN, Logger.Level.INFORMATION, "Train #" + id + " sees main signal #" +
            signal.getId() + " showing " + signal.getDisplay() + "." );
        drivingControl.mainSignalAhead( signal.getDisplay() );
      }
    }
  }

  /**
   * Returns how many tracks are occupied by this train.
   * @return  The number of occupied tracks
   */
  public Object getTrackOccupiedCount() {
    return tracksOccupied.size();
  }

  /**
   * Draws this train into a graphics context.
   * @param g  the graphics context
   */
  public void draw(Graphics g) {
    // TODO: The lines after return will only draw a circle...
    return;
   
//    Coordinates coord1 = head.getPosition().getNode().getCoordinates();
//    Coordinates coord2 = tail.getPosition().getNode().getCoordinates();
//   
//    if ( coord1 != null && coord2 != null ) {
//      g.setColor( Color.BLUE );
//
//      int x = ( coord1.getX() + coord2.getX() ) / 2;
//      int y = ( coord1.getY() + coord2.getY() ) / 2;
//     
//      g.fillOval( x, y, 15, 15 );
//    }
  }

  void setDrivingControl( DrivingControl drivingControl ) {
    this.drivingControl = drivingControl;
  }

  public DrivingControl getDrivingControl() {
    return drivingControl;
  }
 
  public String toString() {
    TrackPosition pos = null;

    String out = String.format( "Train: %d, Train group: %d\n",
        getId(), getTrainGroup().getId() );
    pos = getHead().getPosition();
    out += String.format( "Current position of head: track: %d, node: %d, away: %d\n" ,
        pos.getTrack().getId(),
        pos.getNode().getId(), pos.getDistance()
    );
    pos = getTail().getPosition();
    out += String.format( "Current position of tail: track: %d, node: %d, away: %d\n",
        pos.getTrack().getId(),
        pos.getNode().getId(), pos.getDistance()
    );
    out += String.format( "Length: %d\n", getLength() );
    out += String.format( "Driving direction: %s\n", ( getDirection() == DrivingControl.Direction.FORWARD ? "forward" : ( getDirection() == DrivingControl.Direction.BACKWARD ? "backward" : "undefined" ) ) );
    out += String.format( "Driving mode: %s\n", drivingControl.getDrivingMode() );
    out += String.format( "Total distance travelled: %d\n", getDistanceTravelled() );
    out += String.format( "Tracks occupied: %d\n", getTrackOccupiedCount() );

    out += String.format( "\nSpeed: %d\n", getTrainGroup().getCurrentSpeed() );

    return out;
  }

}
TOP

Related Classes of net.sf.mrailsim.trains.Train

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.