From 11e4fde5863b1c1f7d7879f8d1e68c7d6dca4256 Mon Sep 17 00:00:00 2001
From: brutzman <brutzman@nps.edu>
Date: Sat, 1 Jan 2022 22:34:09 -0800
Subject: [PATCH] Class to represent Track from list of PDUs

---
 examples/src/OpenDis7Examples/PduTrack.java | 320 ++++++++++++++++++++
 1 file changed, 320 insertions(+)
 create mode 100644 examples/src/OpenDis7Examples/PduTrack.java

diff --git a/examples/src/OpenDis7Examples/PduTrack.java b/examples/src/OpenDis7Examples/PduTrack.java
new file mode 100644
index 0000000000..f96abb1aff
--- /dev/null
+++ b/examples/src/OpenDis7Examples/PduTrack.java
@@ -0,0 +1,320 @@
+/*
+Copyright (c) 1995-2021 held by the author(s).  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer
+      in the documentation and/or other materials provided with the
+      distribution.
+    * Neither the names of the Naval Postgraduate School (NPS)
+      Modeling Virtual Environments and Simulation (MOVES) Institute
+      https://www.nps.edu and https://www.nps.edu/web/moves
+      nor the names of its contributors may be used to endorse or
+      promote products derived from this software without specific
+      prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+*/
+// TODO move into open-dis7 distribution tree in package edu.nps.moves.dis7.utilities.stream;
+
+package OpenDis7Examples;
+
+import edu.nps.moves.dis7.enumerations.DisPduType;
+import edu.nps.moves.dis7.pdus.EntityStatePdu;
+import edu.nps.moves.dis7.pdus.EulerAngles;
+import edu.nps.moves.dis7.pdus.Pdu;
+import edu.nps.moves.dis7.pdus.Vector3Double;
+import java.util.ArrayList;
+
+/**
+ * Create a track from DIS ESPDUs
+ * @author brutzman
+ */
+public class PduTrack {
+    
+    private ArrayList<Pdu> pduList = new ArrayList<>();
+    
+    private ArrayList<Vector3Double> waypointsList = new ArrayList<>();
+    private ArrayList<EulerAngles>      anglesList = new ArrayList<>();
+    private ArrayList<Integer>       timestampList = new ArrayList<>();
+    
+    private String      descriptor = new String();
+    private String                   x3dTimeSensorDEF = new String();
+    private String         x3dPositionInterpolatorDEF = new String();
+    private String      x3dOrientationInterpolatorDEF = new String();
+    
+    private String TRACE_PREFIX = "[" + (PduTrack.class.getSimpleName()) + "] ";
+    
+    /**
+     * Constructor design goal: additional built-in initialization conveniences can go here
+     */
+    public PduTrack()
+    {
+        // Potential constructor is under consideration.  Constructor is not currently needed.
+    }
+    
+    /**
+     * Get simple descriptor (such as parent class name) for this SimulationManager, used in trace statements
+     * @return simple descriptor name
+     */
+    public String getDescriptor() 
+    {
+        return descriptor;
+    }
+    /**
+     * Set new simple descriptor (such as parent class name) for this SimulationManager, used in trace statements
+     * @param newDescriptor simple descriptor name for this interface
+     * @return same object to permit progressive setters */
+    public PduTrack setDescriptor(String newDescriptor) 
+    {
+        if (newDescriptor != null)
+            this.descriptor = newDescriptor.trim();
+        TRACE_PREFIX = "[" + (PduTrack.class.getSimpleName() + " " + descriptor) + "] ";
+        return this;
+    }
+
+    /**
+     * @return the waypointsList
+     */
+    public ArrayList<Vector3Double> getWaypointsList() {
+        return waypointsList;
+    }
+    /**
+     * @return the anglesList
+     */
+    public ArrayList<EulerAngles> getAnglesList() {
+        return anglesList;
+    }
+    /**
+     * @return the timestampList
+     */
+    public ArrayList<Integer> getTimestampList() {
+        return timestampList;
+    }
+    /**
+     * Add PDU, typically ESPDU
+     * @param newPdu new Pdu to add, typically ESPDU
+     * @return same object to permit progressive setters
+     */
+    public PduTrack addPdu(Pdu newPdu)
+    {
+        pduList.add(newPdu);
+        return this;
+    }
+    /**
+     * clear all PDUs
+     * @return same object to permit progressive setters
+     */
+    public PduTrack clearPduLists()
+    {
+              pduList.clear();
+        waypointsList.clear();
+           anglesList.clear();
+        timestampList.clear();
+        return this;
+    }
+
+    /**
+     * Provide DEF value if not defined by program
+     * @return the x3dTimeSensorDEF
+     */
+    public String getX3dTimeSensorDEF() {
+        if    (x3dTimeSensorDEF.isEmpty())
+               x3dTimeSensorDEF = getDescriptor().replace(" ", "") + "Clock";
+        return x3dTimeSensorDEF;
+    }
+
+    /**
+     * Set DEF value for X3D node
+     * @param x3dTimeSensorDEF the x3dTimeSensorDEF to set
+     */
+    public void setX3dTimeSensorDEF(String x3dTimeSensorDEF) {
+        this.x3dTimeSensorDEF = x3dTimeSensorDEF;
+    }
+
+    /**
+     * Provide DEF value if not defined by program
+     * @return the x3dPositionInterpolatorDEF
+     */
+    public String getX3dPositionInterpolatorDEF() {
+        if    (x3dPositionInterpolatorDEF.isEmpty())
+               x3dPositionInterpolatorDEF = getDescriptor().replace(" ", "") + "Positions";
+        return x3dPositionInterpolatorDEF;
+    }
+
+    /**
+     * Set DEF value for X3D node
+     * @param x3dPositionInterpolatorDEF the x3dPositionInterpolatorDEF to set
+     */
+    public void setX3dPositionInterpolatorDEF(String x3dPositionInterpolatorDEF) {
+        this.x3dPositionInterpolatorDEF = x3dPositionInterpolatorDEF;
+    }
+
+    /**
+     * Provide DEF value if not defined by program
+     * @return the x3dOrientationInterpolatorDEF
+     */
+    public String getX3dOrientationInterpolatorDEF() {
+        if    (x3dOrientationInterpolatorDEF.isEmpty())
+               x3dOrientationInterpolatorDEF = getDescriptor().replace(" ", "") + "Orientations";
+        return x3dOrientationInterpolatorDEF;
+    }
+
+    /**
+     * Set DEF value for X3D node
+     * @param x3dOrientationInterpolatorDEF the x3dOrientationInterpolatorDEF to set
+     */
+    public void setX3dOrientationInterpolatorDEF(String x3dOrientationInterpolatorDEF) {
+        this.x3dOrientationInterpolatorDEF = x3dOrientationInterpolatorDEF;
+    }
+
+    /**
+     * Sort all points by timestamp
+     * @return same object to permit progressive setters
+     */
+    public PduTrack sortPdus()
+    {
+        // TODO
+        // https://stackoverflow.com/questions/16252269/how-to-sort-an-arraylist
+        return this;
+    }
+    /**
+     * Compute track duration in timestamp ticks
+     * @return duration in timestamp ticks between initial and final ESPDU timestamps in waypointList
+     */
+    public int getTrackDurationTicks()
+    {
+        int initialTime = -1;
+        int   finalTime = -1;
+        int    duration = -1; // used if pduList is empty
+        
+        for (Pdu nextPdu : pduList)
+        {
+            if (nextPdu.getPduType() == DisPduType.ENTITY_STATE)
+            {
+                if (initialTime == -1)
+                    initialTime = nextPdu.getTimestamp();
+                finalTime = nextPdu.getTimestamp();
+            }
+        }
+        if ((initialTime >= 0) && (finalTime >= 0))
+             duration = (finalTime - initialTime);
+        if (pduList.isEmpty())
+        {
+            System.out.println(TRACE_PREFIX + "getTrackDuration() computed illegal duration=" + duration + " due to empty pdu list");
+        }
+        else if ((duration <= 0))
+        {
+            System.out.println(TRACE_PREFIX + "getTrackDuration() computed illegal duration=" + duration + " due to illegal pdu list");
+        }
+        return duration;
+    }
+    /**
+     * Compute track duration in seconds
+     * @return duration in seconds between initial and final ESPDU timestamps in waypointList
+     */
+    public float getTrackDurationSeconds()
+    {
+        float durationSeconds = getTrackDurationTicks() * 1.0f; // TODO convert
+        return durationSeconds;
+    }
+    /**
+     * Create waypoints and angles using all PDU points
+     * @return same object to permit progressive setters
+     */
+    public PduTrack createRawWaypoints()
+    {
+        // https://stackoverflow.com/questions/6536094/java-arraylist-copy
+        
+        getWaypointsList().clear();
+           getAnglesList().clear();
+        for (Pdu nextPdu : pduList)
+        {
+            if (nextPdu.getPduType() == DisPduType.ENTITY_STATE)
+            {
+                EntityStatePdu espdu = (EntityStatePdu)nextPdu;
+                getWaypointsList().add(espdu.getEntityLocation());
+                   getAnglesList().add(espdu.getEntityOrientation());
+                getTimestampList().add(espdu.getTimestamp());
+            }
+        }
+        return this;
+    }
+    /**
+     * Create TimeSensor from Pdu list
+     * @return X3D TimeSensor as string
+     */
+    public String createX3dTimeSensorString()
+    {
+        StringBuilder sb = new StringBuilder();
+        sb.append("<TimeSensor");
+        sb.append(" DEF='").append(getX3dTimeSensorDEF()).append("'");
+        sb.append(" cycleInterval='").append(String.valueOf(getTrackDurationSeconds())).append("'");
+        sb.append(" loop='true'");
+        sb.append("/>");
+        
+        return sb.toString();
+    }
+    /**
+     * Create TimeSensor from Pdu list
+     * @return X3D TimeSensor as string
+     */
+    public String createX3dPositionInterpolatorString()
+    {
+        StringBuilder sb = new StringBuilder();
+        sb.append("<PositionInterpolator");
+        sb.append(" DEF='").append(getX3dPositionInterpolatorDEF()).append("'");
+        sb.append(" key='");
+        for (int i = 0; i < timestampList.size(); i++)
+        {
+            float nextDuration = timestampList.get(i) * 1.0f; // TODO convert
+            sb.append(String.valueOf(nextDuration));
+            if (i < timestampList.size() - 1)
+                sb.append(" ");
+        }
+        sb.append("'");
+        sb.append("/>");
+        
+        return sb.toString();
+    }
+    
+    /** Self test to check basic operation, invoked by main() */
+    public void selfTest()
+    {
+        // TODO
+    }
+    
+    /**
+     * Main method for testing.
+     * @see <a href="https://docs.oracle.com/javase/tutorial/getStarted/application/index.html">Java Tutorials: A Closer Look at the "Hello World!" Application</a>
+     * @param args [address, port, descriptor] command-line arguments are an array of optional String parameters that are passed from execution environment during invocation
+     */
+    public static void main(String[] args)
+    {
+        System.out.println("*** PduTrack main() self test started...");
+          
+        PduTrack pduTrack = new PduTrack();
+        
+        pduTrack.setDescriptor("main() self test");
+        
+        pduTrack.selfTest();
+        
+        System.out.println("*** PduTrack main() self test complete.");
+    }
+}
-- 
GitLab