/*
* JaamSim Discrete Event Simulation
* Copyright (C) 2016 JaamSim Software Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jaamsim.Examples;
import com.jaamsim.Graphics.DisplayEntity;
import com.jaamsim.Samples.SampleInput;
import com.jaamsim.basicsim.EntityTarget;
import com.jaamsim.events.ProcessTarget;
import com.jaamsim.input.Keyword;
import com.jaamsim.input.Output;
import com.jaamsim.input.Vec3dInput;
import com.jaamsim.math.MathUtils;
import com.jaamsim.math.Vec3d;
import com.jaamsim.units.DimensionlessUnit;
import com.jaamsim.units.DistanceUnit;
import com.jaamsim.units.RateUnit;
import com.jaamsim.units.TimeUnit;
/**
* Example of how to create a new simulation object in JaamSim. The demo entity travels back and
* forth between two nodes with a specified travel time.
*/
public class DemoEntity extends DisplayEntity {
@Keyword(description = "The time required to travel from one end of the route to the other.\n"
+ "Accepts a number, an object that returns a number, or an expression "
+ "that returns a number. In each case, the number must have the units "
+ "of time.",
exampleList = { "3.0 h", "NormalDistribution1",
"'1[s] + 0.5*[TimeSeries1].PresentValue'" })
private final SampleInput travelTime;
@Keyword(description = "The position of the first node.",
exampleList = {"1.5 0 0 m"})
protected final Vec3dInput node1;
@Keyword(description = "The position of the second node.",
exampleList = {"1.5 0 0 m"})
protected final Vec3dInput node2;
private double lastUpdateTime; // time at which the distance was calculated
private double distance; // relative position between node1 and node2 (node1 = 0, node2 = 1)
private double speed; // relative speed of the entity between node1 and node2
private long numberOfTrips; // number of times the entity has travelled between the nodes
{
travelTime = new SampleInput("TravelTime", "Key Inputs", null);
travelTime.setUnitType(TimeUnit.class);
travelTime.setEntity(this);
travelTime.setRequired(true);
travelTime.setValidRange(1.0e-6, Double.POSITIVE_INFINITY);
this.addInput(travelTime);
node1 = new Vec3dInput("Node1", "Key Inputs", new Vec3d(0.0, 0.0, 0.0));
node1.setUnitType(DistanceUnit.class);
this.addInput(node1);
node2 = new Vec3dInput("Node2", "Key Inputs", new Vec3d(1.0, 0.0, 0.0));
node2.setUnitType(DistanceUnit.class);
this.addInput(node2);
}
public DemoEntity() {}
@Override
public void earlyInit() {
super.earlyInit();
lastUpdateTime = 0.0;
distance = 0.0;
speed = 0.0;
numberOfTrips = 0;
}
@Override
public void startUp() {
super.startUp();
this.startTravel();
}
/**
* Starts a new trip from one node to the other
*/
private void startTravel() {
// Set the duration for the trip
double simTime = this.getSimTime();
double duration = travelTime.getValue().getNextSample(simTime);
// Set the speed
speed = 1.0 / duration;
if (MathUtils.near(distance, 1.0)) {
speed = -speed;
}
lastUpdateTime = simTime;
// Schedule the time at which the entity will reach the next node
this.scheduleProcess(duration, 5, endTravelTarget, null);
}
/**
* Ends the trip at the next node
*/
public void endTravel() {
// Update the entity's relative position
double simTime = this.getSimTime();
distance += this.getDistanceTravelled(simTime);
// Adjust the relative distance to avoid round-off error
if (MathUtils.near(distance, 0.0)) {
distance = 0.0;
}
if (MathUtils.near(distance, 1.0)) {
distance = 1.0;
}
// Count the number of trips
numberOfTrips++;
// Start the next trip
this.startTravel();
}
/**
* EndActionTarget
*/
private static class EndTravelTarget extends EntityTarget<DemoEntity> {
EndTravelTarget(DemoEntity ent) {
super(ent, "endTravel");
}
@Override
public void process() {
ent.endTravel();
}
}
private final ProcessTarget endTravelTarget = new EndTravelTarget(this);
/**
* Returns the relative distance travelled by the entity since the last update
* @param simTime - present simulation time
* @return relative distance travelled
*/
private double getDistanceTravelled(double simTime) {
return (simTime - lastUpdateTime)*speed;
}
@Override
public void updateGraphics(double simTime) {
// Leave the entity in its present position until the simulation starts
if (simTime == 0.0)
return;
// Calculate the relative position of the entity at this time
double dist = distance + this.getDistanceTravelled(simTime);
// Set the entity's position
Vec3d pos = new Vec3d();
pos.interpolate3(node1.getValue(), node2.getValue(), dist);
this.setGlobalPosition(pos);
}
@Output(name = "NumberOfTrips",
description = "Number of times the entity has travelled in either direction between the "
+ "two nodes.",
unitType = DimensionlessUnit.class,
reportable = true,
sequence = 1)
public long getNumberOfTrips(double simTime) {
return numberOfTrips;
}
@Output(name = "RelativePosition",
description = "Position of the entity between the two nodes: Node1 = 0, Node2 = 1.",
unitType = DistanceUnit.class,
reportable = false,
sequence = 2)
public double getRelativePosition(double simTime) {
return distance + this.getDistanceTravelled(simTime);
}
@Output(name = "RelativeSpeed",
description = "Speed of the entity expressed as the change in relative position per unit "
+ "time.",
unitType = RateUnit.class,
reportable = false,
sequence = 3)
public double getRelativeSpeed(double simTime) {
return speed;
}
}