/* * 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; } }