/** * Copyright (c) 2008-2022, MOVES Institute, Naval Postgraduate School (NPS). All rights reserved. * This work is provided under a BSD open-source license, see project license.html and license.txt * * @author brutzman@nps.edu */ package OpenDis7Examples; import edu.nps.moves.dis7.entities.swe.platform.surface._001Poseidon; import edu.nps.moves.dis7.enumerations.ForceID; import edu.nps.moves.dis7.pdus.EntityStatePdu; import edu.nps.moves.dis7.pdus.Pdu; import edu.nps.moves.dis7.pdus.Vector3Double; import edu.nps.moves.dis7.utilities.DisChannel; import edu.nps.moves.dis7.utilities.DisTime; import edu.nps.moves.dis7.utilities.stream.X3dCreateInterpolators; import edu.nps.moves.dis7.utilities.stream.X3dCreateLineSet; import java.util.ArrayList; import java.util.logging.Level; import java.util.logging.Logger; /** * The purpose of this program is to provide an easily modifiable example * simulation for networked entity tracks and presentation, including * DIS-capable entities doing tasks and reporting them to the network. * Default settings include PDU recording turned on by default. * @see <a href="https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleTrackInterpolationLog.txt" target="_blank">ExampleTrackInterpolationLog.txt</a> * @see <a href="https://calhoun.nps.edu/handle/10945/65436" target="_blank">REPEATABLE UNIT TESTING OF DISTRIBUTED INTERACTIVE SIMULATION (DIS) PROTOCOL BEHAVIOR STREAMS USING WEB STANDARDS</a> by Tobias Brennenstuhl, Masters Thesis, Naval Postgraduate School (NPS), June 2020 * @see <a href="https://gitlab.nps.edu/Savage/SavageTheses/-/tree/master/BrennenstuhlTobias" target="_blank">https://gitlab.nps.edu/Savage/SavageTheses/-/tree/master/BrennenstuhlTobias</a> */ public class ExampleTrackInterpolation extends ExampleSimulationProgram { /** Default constructor */ public ExampleTrackInterpolation() { // default constructor } // -------------------- Begin Variables for X3D autogenerated code private X3dCreateInterpolators x3dInterpolators = new X3dCreateInterpolators(); private X3dCreateLineSet x3dLineSet = new X3dCreateLineSet(); private byte[] globalByteBufferForX3dInterpolators = null; // -------------------- End Variables for X3D autogenerated code ArrayList<Pdu> pduSentList = new ArrayList<>(); /** * This runSimulationLoops() method is a programmer-modifiable method for * defining and running a new simulation of interest. Welcome! Other parts * of this program handle bookkeeping and plumbing tasks so that you can * focus on your model entities and activities. Expandable support includes * DIS EntityStatePdu, FirePdu and CommentPdu all available for modification * and sending in a simulation loop. Continuous improvement efforts seek to * make this program as easy and straightforward as possible for DIS * simulationists to use and adapt. All of the other methods are setup, * teardown and configuration that you may find interesting, even helpful, * but don't really have to worry about. */ @SuppressWarnings("SleepWhileInLoop") // yes we do that @Override // indicates that this method supercedes corresponding superclass method public void runSimulationLoops() { try { final int SIMULATION_MAX_LOOP_COUNT = 50; // be deliberate out there! also avoid infinite loops. int simulationLoopCount = 0; // variable, initialized at 0 boolean simulationComplete = false; // sentinel variable as termination condition, are we done yet? // TODO reset Clock Time to today's date and timestamp to zero, providing consistent outputs for each simulation run DisTime.setEpochLvcNow(); simulationTimeSeconds = simulationTimeInitial - getSimulationTimeStepDuration(); // pre-initialization for first loop initializeSimulationEntities(); // use declared PDU objects and set their values. entityID_1.setSiteID(1).setApplicationID(2).setEntityID(3); // made-up example ID; // TODO someday, use enumerations; is there a unique site triplet for MOVES Institute? disChannel.getPduRecorder().setVerbose(false); disChannel.getPduRecorder().hasVerboseOutput(); // debug check EntityStatePdu espdu_1 = pduFactory.makeEntityStatePdu(); espdu_1.setEntityID(entityID_1); espdu_1.setForceId(ForceID.FRIENDLY); espdu_1.setEntityType(new _001Poseidon()); // note import statement above espdu_1.setMarking("track path"); // espdu_1.clearMarking(); // test // espdu_1.getMarkingString(); // trace // espdu_1.setEntityLocation(new Vector3Double().setX(0).setY(0).setZ(0)); // long form espdu_1.setEntityLocation(0, 0, 0); // utility method float speedEntity_1 = 1.0f; // meters/second EntityStatePdu.Direction directionEntity_1 = EntityStatePdu.Direction.NORTH; PduTrack pduTrack_1 = new PduTrack(); pduTrack_1.setDescriptor("testing 123"); pduTrack_1.setDefaultWaypointInterval(1.0f); // overrides timestamps pduTrack_1.setAddLineBreaksWithinKeyValues(true); pduTrack_1.setAuthor("Don Brutzman"); pduTrack_1.setX3dModelName("ExampleTrackInterpolation.x3d"); pduTrack_1.setX3dModelIdentifier("https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/-/blob/master/examples/src/OpenDis7Examples/ExampleTrackInterpolation.x3d"); pduTrack_1.addPdu(espdu_1); // initial location // OK send initial PDUs prior to loop if (disChannel.getPduRecorder().hasVerboseOutput()) System.out.println("sending PDUs for simulation step " + simulationLoopCount + ", monitor loopback to confirm sent"); disChannel.sendSinglePdu(espdu_1); // sendCommentPdu(timeStepDurationCommentType, narrativeMessage1, narrativeMessage2, narrativeMessage3); pduSentList.add(espdu_1); reportPdu(simulationLoopCount, espdu_1.getEntityLocation(), directionEntity_1); // TODO simulation management PDUs for startup, planning to design special class support // =================================================================================================== // loop the simulation while allowed, programmer can set additional conditions to break out and finish while (simulationLoopCount < SIMULATION_MAX_LOOP_COUNT) // are we done yet? { simulationLoopCount++; // good practice: increment loop counter as first action in that loop simulationTimeSeconds += getSimulationTimeStepDuration(); // good practice: update clock along with loop index // ============================================================================================= // * your own simulation code starts here! ***************************************************** // ============================================================================================= // are there any other variables to modify at the beginning of your loop? // compute a track, update an ESPDU, whatever it is that your model is doing... // Pick direction, change each 10 seconds, traverse a box. No physics. Walk a box! if (simulationLoopCount <= 10) directionEntity_1 = EntityStatePdu.Direction.NORTH; else if (simulationLoopCount <= 20) directionEntity_1 = EntityStatePdu.Direction.EAST; else if (simulationLoopCount <= 30) directionEntity_1 = EntityStatePdu.Direction.SOUTH; else // if (simulationLoopCount <= 40) directionEntity_1 = EntityStatePdu.Direction.WEST; // use utility method to simply update velocity vector using speed value and direction espdu_1.setEntityLinearVelocity(speedEntity_1, directionEntity_1); // Where is my entity? Insert changes in position; this sample only changes X position. espdu_1.advanceEntityLocation(getSimulationTimeStepDuration()); // make your reports: narrative code for CommentPdu here (set all to empty strings to avoid sending) narrativeMessage1 = "MV3500 TrackSimulationProgram"; narrativeMessage2 = "runSimulation() loop " + simulationLoopCount + " at time " + simulationTimeSeconds; narrativeMessage3 = ""; // intentionally blank for testing // your loop termination condition goes here if (simulationLoopCount > 40) // for example { simulationComplete = true; } // ============================================================================================= // * your own simulation code is finished here! ************************************************ // ============================================================================================= // staying synchronized with timestep: wait duration for elapsed time in this loop // Thread.sleep needs a (long) parameter for milliseconds, which are clumsy to use sometimes if (false) // real-time operation or simulation speedup { Thread.sleep((long) (getSimulationTimeStepDuration() * 1000)); // seconds * (1000 msec/sec) = milliseconds System.out.println(disChannel.getTRACE_PREFIX() + "Pausing for " + getSimulationTimeStepDuration() + " seconds"); } // OK now send the status PDUs for this loop, and then continue if (disChannel.getPduRecorder().hasVerboseOutput()) System.out.println("sending PDUs for simulation step " + simulationLoopCount + ", monitor loopback to confirm sent"); disChannel.sendSinglePdu(espdu_1); disChannel.sendCommentPdu(DisChannel.COMMENTPDU_SIMULATION_TIMESTEP, narrativeMessage1, narrativeMessage2, narrativeMessage3); if (disChannel.getPduRecorder().hasVerboseOutput()) System.out.println(disChannel.getTRACE_PREFIX() + "PDUs successfully sent for this loop"); pduSentList.add(espdu_1); pduTrack_1.addPdu(espdu_1); Vector3Double location = espdu_1.getEntityLocation(); reportPdu(simulationLoopCount, location, directionEntity_1); // =============================== // current loop now finished, check whether to terminate if simulation complete, otherwise continue if (simulationComplete || (simulationLoopCount > 10000)) // for example; including fail-safe condition is good { System.out.println(disChannel.getTRACE_PREFIX() + "loop termination condition met, simulationComplete=" + simulationComplete); // ", final loopCount=" + loopCount + break; } } // end of simulation loop // =================================================================================================== System.out.println(disChannel.getTRACE_PREFIX() + "all PDUs successfully sent for this loop (pduSentList.size()=" + pduSentList.size() + " total)"); // track analysis System.out.println(disChannel.getTRACE_PREFIX() + "pduTrack_1 initialLocation=" + pduTrack_1.getInitialLocation() + ", latestLocation=" + pduTrack_1.getLatestLocation()); pduTrack_1.sortPdus() .createRawWaypoints(); System.out.println("pduTrack_1 getEspduCount()=" + pduTrack_1.getEspduCount()); System.out.println("pduTrack_1 duration = " + pduTrack_1.getTotalDurationSeconds() + " seconds = " + pduTrack_1.getTotalDurationTicks() + " ticks"); System.out.println("================================="); System.out.println(pduTrack_1.createX3dModel()); System.out.println("================================="); narrativeMessage2 = "runSimulation() completed successfully"; // all done disChannel.sendCommentPdu(DisChannel.COMMENTPDU_NARRATIVE, narrativeMessage1, narrativeMessage2, narrativeMessage3); if (disChannel.getPduRecorder().hasVerboseOutput()) disChannel.printlnTRACE("final CommentPdu successfully sent for simulation"); // TODO simulation management PDUs } catch (InterruptedException iex) // handle any exception that your code might choose to provoke! { Logger.getLogger(ExampleTrackInterpolation.class.getSimpleName()).log(Level.SEVERE, null, iex); } } /** * Report current PDU information to console * @param simulationLoopCount current loop index * @param location current location * @param directionEntity current direction * @return same object to permit progressive setters */ public ExampleTrackInterpolation reportPdu(int simulationLoopCount, Vector3Double location, EntityStatePdu.Direction directionEntity) { System.out.println (String.format("%2d ", simulationLoopCount) + "Entity location=(" + String.format("%4.1f", location.getX()) + ", " + String.format("%4.1f", location.getY()) + ", " + String.format("%4.1f", location.getZ()) + ") " + String.format("%-5s", directionEntity.name()) // + " " + espdu_1.getEntityLinearVelocity().toString() ); return this; } /* Default constructors used unless otherwise defined/overridden. */ /** * Main method is first executed when a program instance is loaded. * * @see * <a href="https://docs.oracle.com/javase/tutorial/getStarted/application/index.html" target="_blank">Java * Tutorials: A Closer Look at the "Hello World!" Application</a> * @param args command-line arguments are an array of optional String * parameters that are passed from execution environment during invocation */ public static void main(String[] args) { thisProgram = new ExampleTrackInterpolation(); // create instance of self within static main() method thisProgram.disChannel.printlnTRACE("main() started..."); thisProgram.handleArguments (args); // process command-line invocation arguments // thisProgram.disChannel.getPduRecorder().setVerbose(false); // thisProgram.disChannel.setVerboseComments(false); // thisProgram.disChannel.getDisNetworkInterface().setVerbose(false); thisProgram.runSimulationLoops(); // ... your simulation execution code goes in there ... thisProgram.disChannel.tearDownNetworkInterface(); // make sure no processes are left lingering thisProgram.disChannel.printlnTRACE("complete."); // report successful completion System.exit(0); // ensure all threads and sockets released } }