diff --git a/src/edu/nps/moves/dis7/examples/AlphabeticalPduSender.java b/src/edu/nps/moves/dis7/examples/AlphabeticalPduSender.java
index c7ad7ce61bf2e569148c5d21c6f47acbb07e0a53..3dd2989c1ef6629b8755f62158b86d6febdd703e 100644
--- a/src/edu/nps/moves/dis7/examples/AlphabeticalPduSender.java
+++ b/src/edu/nps/moves/dis7/examples/AlphabeticalPduSender.java
@@ -1,7 +1,7 @@
 package edu.nps.moves.dis7.examples;
 
 import edu.nps.moves.dis7.pdus.*;
-import edu.nps.moves.dis7.enumerations.DISPDUType;
+import edu.nps.moves.dis7.enumerations.DisPduType;
 import edu.nps.moves.dis7.utilities.DisThreadedNetworkInterface;
 
 import java.io.ByteArrayOutputStream;
@@ -57,7 +57,7 @@ public class AlphabeticalPduSender
 
       // Loop through all the enumerated PDU types, create a PDU for each type,
       // and add that PDU to a list.
-      for (DISPDUType pdu : DISPDUType.values()) { // results are in alphabetic, not numeric order
+      for (DisPduType pdu : DisPduType.values()) { // results are in alphabetic, not numeric order
           
         Pdu aPdu = null;
 
diff --git a/src/edu/nps/moves/dis7/examples/EntityStateEntityIdExampleUse.java b/src/edu/nps/moves/dis7/examples/EntityStateEntityIdExampleUse.java
index df998e64a1661ea5e6a290e7b4b917462a77cc65..c26806478a9f506dc0ca50aacfcdbb87defa063c 100644
--- a/src/edu/nps/moves/dis7/examples/EntityStateEntityIdExampleUse.java
+++ b/src/edu/nps/moves/dis7/examples/EntityStateEntityIdExampleUse.java
@@ -8,7 +8,7 @@ package edu.nps.moves.dis7.examples;
 import edu.nps.moves.dis7.pdus.EntityStatePdu;
 import edu.nps.moves.dis7.pdus.Pdu;
 import edu.nps.moves.dis7.utilities.PduFactory;
-import edu.nps.moves.dis7.enumerations.DISPDUType;
+import edu.nps.moves.dis7.enumerations.DisPduType;
 import edu.nps.moves.dis7.utilities.DisThreadedNetworkInterface;
 import java.io.IOException;
 import edu.nps.moves.dis7.entities.usa.platform.surface.*;
@@ -100,7 +100,7 @@ public class EntityStateEntityIdExampleUse
     
     /* Do the same for the second way of creating a Shenandoah entity type and show an alternate way of creating an ESPDU */
     
-    espdu = (EntityStatePdu)pduFactory.createPdu(DISPDUType.ENTITY_STATE);
+    espdu = (EntityStatePdu)pduFactory.createPdu(DisPduType.ENTITY_STATE);
     /* set desired entity state fields here */
 
     AD44Shenandoah entityType2 = new AD44Shenandoah(); // edu.nps.moves.dis7.entities.usa.platform.surface
diff --git a/src/edu/nps/moves/dis7/utilities/DisThreadedNetworkInterface.java b/src/edu/nps/moves/dis7/utilities/DisThreadedNetworkInterface.java
index eb01b41d8ad0a97dad05268edff989ff8cd1cc31..56930ceff82d17af3054e9b5846f14633b4c283c 100644
--- a/src/edu/nps/moves/dis7/utilities/DisThreadedNetworkInterface.java
+++ b/src/edu/nps/moves/dis7/utilities/DisThreadedNetworkInterface.java
@@ -1,525 +1,525 @@
-/**
- * Copyright (c) 2008-2021, 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
- */
-package edu.nps.moves.dis7.utilities;
-
-import edu.nps.moves.dis7.pdus.Pdu;
-import edu.nps.moves.dis7.pdus.DisTime;
-import edu.nps.moves.dis7.enumerations.DISPDUType;
-
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-
-import java.net.*;
-
-import java.nio.ByteBuffer;
-
-import java.util.*;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * This is a thread-safe, multicast DIS network interface class.
- * 
- * @author Mike Bailey, jmbailey@nps.edu
- * @since Jul 29, 2019
- */
-public class DisThreadedNetworkInterface
-{
-    /** Default value */
-    public static String DEFAULT_MULTICAST_ADDRESS = "225.4.5.6";
-
-    /** Default value */
-    public static int DEFAULT_DIS_PORT = 3000;
-
-    private static final String TRACE_PREFIX = "[" + DisThreadedNetworkInterface.class.getName() + "] ";
-    private boolean verbose = true;
-    private boolean verboseIncludesTimestamp = false;
-
-    /**
-     * Pdu listener class and interface
-     */
-    public interface PduListener
-    {
-        /**
-         * Callback method
-         * @param pdu received pdu
-         */
-        void incomingPdu(Pdu pdu);
-    }
-
-    /**
-     * Raw pdu listener class and interface
-     */
-    public interface RawPduListener
-    {
-        /**
-         * Callback method
-         * @param bAndL exposed buffer to receive incoming pdu
-         */
-        void incomingPdu(ByteArrayBufferAndLength bAndL);
-    }
-
-    /**
-     * Stores data for further processing
-     */
-    public class ByteArrayBufferAndLength
-    {
-        /**
-         * Active ByteArray buffer
-         */
-        public byte[] bufferByteArray;
-        /**
-         * Active ByteArray buffer length
-         */
-        public int length;
-
-        /**
-         * Default constructor for data storage
-         *
-         * @param bufferByteArray the data buffer to store
-         * @param length the length of the data buffer
-         */
-        public ByteArrayBufferAndLength(byte[] bufferByteArray, int length)
-        {
-            this.bufferByteArray = bufferByteArray;
-            this.length = length;
-        }
-    }
-
-    /** ********** Begin class ************** */
-    /**
-     * MTU 8192: TODO this has actually been superseded by a larger buffer size,
-     * but good enough for now
-     */
-    public static final int MAX_DIS_PDU_SIZE = 8192;
-
-    /**
-     * MTU 1500: size of an Ethernet frame, common value to avoid packet
-     * segmentation
-     */
-    public static final int MAX_TRANSMISSION_UNIT_SIZE = 1500;
-
-    private int disPort;
-    private String multicastAddress;
-    private boolean killed = false;
-
-    private InetAddress inetAddress;
-    private InetSocketAddress inetSocket;
-    private NetworkInterface networkInterface;
-    private DatagramSocket datagramSocket = null;
-
-    /**
-     * Default constructor using default port and multicast address
-     */
-    public DisThreadedNetworkInterface()
-    {
-        this(DEFAULT_MULTICAST_ADDRESS, DEFAULT_DIS_PORT);
-    }
-
-    /**
-     * Constructor
-     * @param multicastGroup the multicast group address to utilize
-     * @param port the multicast port to utilize
-     */
-    public DisThreadedNetworkInterface(String multicastGroup, int port)
-    {
-        disPort = port;
-        multicastAddress = multicastGroup;
-        try
-        {
-            inetAddress = InetAddress.getByName(multicastAddress);
-        }
-        catch (UnknownHostException ex)
-        {
-            Logger.getLogger(DisThreadedNetworkInterface.class.getName()).log(Level.SEVERE, null, ex);
-        }
-        inetSocket = new InetSocketAddress(inetAddress, disPort);
-        networkInterface = findIpv4Interface();
-        init();
-    }
-
-    /* *********** queues and lists  and public methods ************** */
-    private final List<PduListener> everyTypeListeners = new ArrayList<>();
-    private final Map<DISPDUType, List<PduListener>> typeListeners = new HashMap<>();
-    private final List<RawPduListener> rawListeners = new ArrayList<>();
-    private final LinkedBlockingQueue<Pdu> pdus2send = new LinkedBlockingQueue<>();
-
-    /**
-     * Add a listener to accept only pdus of a given type
-     * @param newListener listener instance implementing the RawPduListener interface
-     * @param disPduType Pdu type
-     */
-    public void addListener(PduListener newListener, DISPDUType disPduType)
-    {
-        if (disPduType == null)
-        {
-            addListener(newListener);
-        }
-        else
-        {
-            List<PduListener> arLis = typeListeners.get(disPduType);
-            if (arLis == null)
-            {
-                arLis = new ArrayList<>();
-                typeListeners.put(disPduType, arLis);
-            }
-            arLis.add(newListener);
-        }
-    }
-
-    /**
-     * Add a listener to accept all pdu types
-     * @param newListener listener instance implementing the RawPduListener interface
-     */
-    public void addListener(PduListener newListener)
-    {
-        everyTypeListeners.add(newListener);
-    }
-
-    /**
-     * Remove previously added listener
-     *
-     * @param priorListener listener instance implementing the RawPduListener interface
-     */
-    public void removeListener(PduListener priorListener)
-    {
-        everyTypeListeners.remove(priorListener);
-
-        typeListeners.entrySet().forEach(entry ->
-        {
-            List<PduListener> arLis = entry.getValue();
-            if (arLis.contains(priorListener))
-            {
-                arLis.remove(priorListener);
-            }
-        });
-        // additional sleep, hopefully allowing teardown to proceed to completion
-        sleep(100l); // TODO needed?
-    }
-
-    /**
-     * Add a listener to accept pdus of all types in the form of a byte array
-     *
-     * @param lis listener instance implementing the RawPduListener interface
-     */
-    public void addRawListener(RawPduListener lis)
-    {
-        rawListeners.add(lis);
-    }
-
-    /**
-     * Remove previously added raw listener
-     *
-     * @param lis listener instance implementing the RawPduListener interface
-     */
-    public void removeRawListener(RawPduListener lis)
-    {
-        rawListeners.remove(lis);
-        // additional sleep, hopefully allowing teardown to proceed to completion
-        sleep(100l); // TODO needed?
-    }
-
-    /**
-     * Get current port value
-     * @return current port value
-     */
-    public int getDisPort()
-    {
-        return disPort;
-    }
-
-    /**
-     * Get current multicast address value
-     * @return current multicast address value
-     */
-    public String getMulticastGroup()
-    {
-        return multicastAddress;
-    }
-
-    /**
-     * Send the given pdu to the network using the IP address and port given to the constructor
-     * @param pdu the pdu to send
-     */
-    public void send(Pdu pdu)
-    {
-        pdus2send.add(pdu);
-    }
-
-    /* *************** networking i/o ************* */
-    private PduFactory pduFactory = new PduFactory();
-
-    private Thread sender;
-    private Thread receiver;
-
-    /** Initialization */
-    private void init()
-    {
-        createDatagramSocket(); // common asset, synchronized to prevent interleaved reentry
-
-        receiver = new Thread(receiveThread, TRACE_PREFIX + " receive thread");
-        receiver.setDaemon(true);
-        receiver.setPriority(Thread.NORM_PRIORITY);
-        receiver.start();
-
-        sender = new Thread(sendThread, TRACE_PREFIX + " send thread");
-        sender.setDaemon(true);
-        sender.setPriority(Thread.NORM_PRIORITY);
-        sender.start();
-    }
-
-    /**
-     * Create datagram socket if not already available; can also be invoked by
-     * either sender or receiver thread to ensure datagram socket is open.
-     * Synchronized method to prevent interleaved reentry.
-     * @see <a href="https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html">Java Tutorials: Synchronized Methods</a>
-     */
-    private synchronized void createDatagramSocket()
-    {
-        boolean closedSocket = false;
-        if ((datagramSocket != null) && datagramSocket.isClosed())
-        {
-            closedSocket = true;
-            System.err.println(" *** " + TRACE_PREFIX + "datagramSocket.isClosed() unexpectedly, retrying...");
-        }
-        if ((datagramSocket == null) || closedSocket)
-        {
-            try
-            {
-                // The initial value of the SO_BROADCAST socket option is FALSE
-                datagramSocket = new MulticastSocket(getDisPort());
-                ((MulticastSocket) datagramSocket).joinGroup(inetSocket, networkInterface);
-            }
-            catch (IOException ex)
-            {
-                System.err.println(" *** " + TRACE_PREFIX + "Exception in DisThreadedNetworkInterface receive thread: " + ex.getLocalizedMessage());
-            }
-        }
-    }
-  
-    private Runnable receiveThread = () -> {
-
-        int counter = 0;
-
-        // The capacity could go up to MAX_DIS_PDU_SIZE, but this should be good for now
-        // The raw listeners will strip off any extra padding and process what is
-        // required
-        ByteBuffer byteBuffer = ByteBuffer.allocate(MAX_TRANSMISSION_UNIT_SIZE);
-        DatagramPacket packet = new DatagramPacket(byteBuffer.array(), byteBuffer.capacity());
-        Pdu pdu;
-
-        while (!killed) { // keep trying on error
-            
-            // If something trips up with the socket, this thread will attempt to
-            // re-establish for both send/receive threads
-            try {
-                createDatagramSocket (); // ensure socket open, recreate if needed, other thread may occur first
-
-                while (!killed)
-                {
-                    datagramSocket.receive(packet); // blocks here waiting for next DIS pdu to be received on multicast IP and specified port
-                    toRawListeners(packet.getData(), packet.getLength());
-
-                    pdu = pduFactory.createPdu(byteBuffer);
-
-                    if (pdu != null)
-                    {
-                        counter++; // TODO experimental, add to generator as a commented-out diagnostic; consider adding diagnostic mode
-                        if (isVerbose())
-                        {
-                            String message = TRACE_PREFIX + counter + ". received " + pdu.getPduType().toString();
-                            if (isVerboseIncludesTimestamp())
-                                message += " (timestamp " + DisTime.timeStampToString(pdu.getTimestamp());
-                            message +=", size " + pdu.getMarshalledSize() + " bytes)";
-                            System.out.println(message);
-                            System.out.flush();
-                        }
-                        toListeners(pdu);
-                    }
-                    byteBuffer.clear();
-                }
-            } 
-            catch (IOException ex) {
-                System.err.println(TRACE_PREFIX + "Exception in DisThreadedNetworkInterface receive thread: " + ex.getLocalizedMessage());
-                System.err.println(TRACE_PREFIX + "Retrying new socket...");
-            } 
-            finally
-            {
-                if (datagramSocket != null && !datagramSocket.isClosed()) {
-                    try {
-                        ((MulticastSocket)datagramSocket).leaveGroup(inetSocket, networkInterface);
-                    } catch (IOException ex) {
-                        Logger.getLogger(DisThreadedNetworkInterface.class.getName()).log(Level.SEVERE, null, ex);
-                    }
-                    datagramSocket.close();
-                    sleep(100l); // TODO needed?
-                    datagramSocket = null;
-                }
-            }
-//      if (!killed)
-//        sleep(250);
-        }
-    };
-
-    private final Runnable sendThread = () -> {
-
-        Pdu pdu;
-
-        // The capacity could go up to MAX_DIS_PDU_SIZE, but this should be good for now
-        ByteArrayOutputStream baos   = new ByteArrayOutputStream(MAX_TRANSMISSION_UNIT_SIZE);
-        DataOutputStream      dos    = new DataOutputStream(baos);
-        DatagramPacket        packet = new DatagramPacket(baos.toByteArray(), baos.size(), inetSocket);
-
-        while (!killed) { // keep trying on error
-
-            // If something trips up with the socket, this thread will attempt to
-            // re-establish for both send/receive threads
-            try {
-                createDatagramSocket (); // ensure socket open, recreate if needed, other thread may occur first
-
-                while (!killed) {
-                    pdu = pdus2send.take();
-
-                    pdu.marshal(dos);
-                    packet.setData(baos.toByteArray());
-                    datagramSocket.send(packet);
-
-                    dos.flush();  // immediately force pdu write
-                    baos.reset();
-                }
-            } 
-            catch (Exception ex)
-            {
-                System.err.println(TRACE_PREFIX + "Exception in DisThreadedNetworkInterface send thread: " + ex.getLocalizedMessage());
-            }
-        }
-        try {
-            dos.close();
-        } catch (IOException e) {}
-    };
-
-    private void toListeners(Pdu pdu) {
-        if (everyTypeListeners.isEmpty()) {
-            return;
-        }
-
-        if (pdu != null) {
-            everyTypeListeners.forEach(lis -> lis.incomingPdu(pdu));
-
-            if (typeListeners.isEmpty()) {
-                return;
-            }
-
-            List<PduListener> arLis = typeListeners.get(pdu.getPduType());
-            if (arLis != null) {
-                arLis.forEach(lis -> lis.incomingPdu(pdu));
-            }
-        }
-    }
-  
-  private void toRawListeners(byte[] data, int len)
-  {
-    if(rawListeners.isEmpty())
-      return;
-    
-    ByteArrayBufferAndLength bl = new ByteArrayBufferAndLength(data, len);
-    rawListeners.forEach(lis->lis.incomingPdu(bl));
-  }
-
-  /** Terminate the instance */
-  public void kill()
-  {
-    killed = true; // set loop sentinel for threads
-  }
-
-  /** Thread sleep for indicated interval
-   * @param duration milliseconds */
-  private void sleep(long duration)
-  {
-    try {
-      Thread.sleep(duration);
-    }
-    catch (InterruptedException ie) 
-    {
-        System.err.flush();
-        System.err.println ("*** " + getClass().getName() + ".sleep(" + duration + ") failed to sleep");
-        ie.printStackTrace(System.err);
-    }
-  }
-
-    /**
-     * Find proper IPV4 interface
-     *
-     * @return a network interface to use to join a multicast group
-     */
-    public static NetworkInterface findIpv4Interface() {
-        try {
-            Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
-            NetworkInterface nif;
-            Enumeration<InetAddress> addresses;
-            InetAddress addr;
-
-            while (ifaces != null && ifaces.hasMoreElements()) {
-                nif = ifaces.nextElement();
-                if (nif.isUp()) {
-                    addresses = nif.getInetAddresses();
-                    while (addresses.hasMoreElements()) {
-                        addr = addresses.nextElement();
-                        if (addr instanceof Inet4Address && !addr.isLoopbackAddress() && !addr.isLinkLocalAddress()) 
-                        {
-                            System.out.println(TRACE_PREFIX + " Using network interface " + nif.getDisplayName());
-                            return nif;
-                        }
-                    }
-                }
-            }
-        } catch (SocketException ex) {
-            Logger.getLogger(DisThreadedNetworkInterface.class.getName()).log(Level.SEVERE, null, ex);
-        }
-        return null;
-    }
-
-    /**
-     * @return the verbose
-     */
-    public boolean isVerbose()
-    {
-        return verbose;
-    }
-
-    /**
-     * @param verbose the verbose to set
-     */
-    public void setVerbose(boolean verbose)
-    {
-        this.verbose = verbose;
-    }
-
-    /**
-     * @return the verboseIncludesTimestamp value
-     */
-    public boolean isVerboseIncludesTimestamp()
-    {
-        return verboseIncludesTimestamp;
-    }
-
-    /**
-     * @param verboseIncludesTimestamp the value to set
-     */
-    public void setVerboseIncludesTimestamp(boolean verboseIncludesTimestamp)
-    {
-        this.verboseIncludesTimestamp = verboseIncludesTimestamp;
-    }
-
-    /**
-     * @param disPort the disPort value to set
-     */
-    public void setDisPort(int disPort)
-    {
-        this.disPort = disPort;
-    }
-}
+/**
+ * Copyright (c) 2008-2021, 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
+ */
+package edu.nps.moves.dis7.utilities;
+
+import edu.nps.moves.dis7.pdus.Pdu;
+import edu.nps.moves.dis7.pdus.DisTime;
+import edu.nps.moves.dis7.enumerations.DisPduType;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import java.net.*;
+
+import java.nio.ByteBuffer;
+
+import java.util.*;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * This is a thread-safe, multicast DIS network interface class.
+ * 
+ * @author Mike Bailey, jmbailey@nps.edu
+ * @since Jul 29, 2019
+ */
+public class DisThreadedNetworkInterface
+{
+    /** Default value */
+    public static String DEFAULT_MULTICAST_ADDRESS = "225.4.5.6";
+
+    /** Default value */
+    public static int DEFAULT_DIS_PORT = 3000;
+
+    private static final String TRACE_PREFIX = "[" + DisThreadedNetworkInterface.class.getName() + "] ";
+    private boolean verbose = true;
+    private boolean verboseIncludesTimestamp = false;
+
+    /**
+     * Pdu listener class and interface
+     */
+    public interface PduListener
+    {
+        /**
+         * Callback method
+         * @param pdu received pdu
+         */
+        void incomingPdu(Pdu pdu);
+    }
+
+    /**
+     * Raw pdu listener class and interface
+     */
+    public interface RawPduListener
+    {
+        /**
+         * Callback method
+         * @param bAndL exposed buffer to receive incoming pdu
+         */
+        void incomingPdu(ByteArrayBufferAndLength bAndL);
+    }
+
+    /**
+     * Stores data for further processing
+     */
+    public class ByteArrayBufferAndLength
+    {
+        /**
+         * Active ByteArray buffer
+         */
+        public byte[] bufferByteArray;
+        /**
+         * Active ByteArray buffer length
+         */
+        public int length;
+
+        /**
+         * Default constructor for data storage
+         *
+         * @param bufferByteArray the data buffer to store
+         * @param length the length of the data buffer
+         */
+        public ByteArrayBufferAndLength(byte[] bufferByteArray, int length)
+        {
+            this.bufferByteArray = bufferByteArray;
+            this.length = length;
+        }
+    }
+
+    /** ********** Begin class ************** */
+    /**
+     * MTU 8192: TODO this has actually been superseded by a larger buffer size,
+     * but good enough for now
+     */
+    public static final int MAX_DIS_PDU_SIZE = 8192;
+
+    /**
+     * MTU 1500: size of an Ethernet frame, common value to avoid packet
+     * segmentation
+     */
+    public static final int MAX_TRANSMISSION_UNIT_SIZE = 1500;
+
+    private int disPort;
+    private String multicastAddress;
+    private boolean killed = false;
+
+    private InetAddress inetAddress;
+    private InetSocketAddress inetSocket;
+    private NetworkInterface networkInterface;
+    private DatagramSocket datagramSocket = null;
+
+    /**
+     * Default constructor using default port and multicast address
+     */
+    public DisThreadedNetworkInterface()
+    {
+        this(DEFAULT_MULTICAST_ADDRESS, DEFAULT_DIS_PORT);
+    }
+
+    /**
+     * Constructor
+     * @param multicastGroup the multicast group address to utilize
+     * @param port the multicast port to utilize
+     */
+    public DisThreadedNetworkInterface(String multicastGroup, int port)
+    {
+        disPort = port;
+        multicastAddress = multicastGroup;
+        try
+        {
+            inetAddress = InetAddress.getByName(multicastAddress);
+        }
+        catch (UnknownHostException ex)
+        {
+            Logger.getLogger(DisThreadedNetworkInterface.class.getName()).log(Level.SEVERE, null, ex);
+        }
+        inetSocket = new InetSocketAddress(inetAddress, disPort);
+        networkInterface = findIpv4Interface();
+        init();
+    }
+
+    /* *********** queues and lists  and public methods ************** */
+    private final List<PduListener> everyTypeListeners = new ArrayList<>();
+    private final Map<DisPduType, List<PduListener>> typeListeners = new HashMap<>();
+    private final List<RawPduListener> rawListeners = new ArrayList<>();
+    private final LinkedBlockingQueue<Pdu> pdus2send = new LinkedBlockingQueue<>();
+
+    /**
+     * Add a listener to accept only pdus of a given type
+     * @param newListener listener instance implementing the RawPduListener interface
+     * @param disPduType Pdu type
+     */
+    public void addListener(PduListener newListener, DisPduType disPduType)
+    {
+        if (disPduType == null)
+        {
+            addListener(newListener);
+        }
+        else
+        {
+            List<PduListener> arLis = typeListeners.get(disPduType);
+            if (arLis == null)
+            {
+                arLis = new ArrayList<>();
+                typeListeners.put(disPduType, arLis);
+            }
+            arLis.add(newListener);
+        }
+    }
+
+    /**
+     * Add a listener to accept all pdu types
+     * @param newListener listener instance implementing the RawPduListener interface
+     */
+    public void addListener(PduListener newListener)
+    {
+        everyTypeListeners.add(newListener);
+    }
+
+    /**
+     * Remove previously added listener
+     *
+     * @param priorListener listener instance implementing the RawPduListener interface
+     */
+    public void removeListener(PduListener priorListener)
+    {
+        everyTypeListeners.remove(priorListener);
+
+        typeListeners.entrySet().forEach(entry ->
+        {
+            List<PduListener> arLis = entry.getValue();
+            if (arLis.contains(priorListener))
+            {
+                arLis.remove(priorListener);
+            }
+        });
+        // additional sleep, hopefully allowing teardown to proceed to completion
+        sleep(100l); // TODO needed?
+    }
+
+    /**
+     * Add a listener to accept pdus of all types in the form of a byte array
+     *
+     * @param lis listener instance implementing the RawPduListener interface
+     */
+    public void addRawListener(RawPduListener lis)
+    {
+        rawListeners.add(lis);
+    }
+
+    /**
+     * Remove previously added raw listener
+     *
+     * @param lis listener instance implementing the RawPduListener interface
+     */
+    public void removeRawListener(RawPduListener lis)
+    {
+        rawListeners.remove(lis);
+        // additional sleep, hopefully allowing teardown to proceed to completion
+        sleep(100l); // TODO needed?
+    }
+
+    /**
+     * Get current port value
+     * @return current port value
+     */
+    public int getDisPort()
+    {
+        return disPort;
+    }
+
+    /**
+     * Get current multicast address value
+     * @return current multicast address value
+     */
+    public String getMulticastGroup()
+    {
+        return multicastAddress;
+    }
+
+    /**
+     * Send the given pdu to the network using the IP address and port given to the constructor
+     * @param pdu the pdu to send
+     */
+    public void send(Pdu pdu)
+    {
+        pdus2send.add(pdu);
+    }
+
+    /* *************** networking i/o ************* */
+    private PduFactory pduFactory = new PduFactory();
+
+    private Thread sender;
+    private Thread receiver;
+
+    /** Initialization */
+    private void init()
+    {
+        createDatagramSocket(); // common asset, synchronized to prevent interleaved reentry
+
+        receiver = new Thread(receiveThread, TRACE_PREFIX + " receive thread");
+        receiver.setDaemon(true);
+        receiver.setPriority(Thread.NORM_PRIORITY);
+        receiver.start();
+
+        sender = new Thread(sendThread, TRACE_PREFIX + " send thread");
+        sender.setDaemon(true);
+        sender.setPriority(Thread.NORM_PRIORITY);
+        sender.start();
+    }
+
+    /**
+     * Create datagram socket if not already available; can also be invoked by
+     * either sender or receiver thread to ensure datagram socket is open.
+     * Synchronized method to prevent interleaved reentry.
+     * @see <a href="https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html">Java Tutorials: Synchronized Methods</a>
+     */
+    private synchronized void createDatagramSocket()
+    {
+        boolean closedSocket = false;
+        if ((datagramSocket != null) && datagramSocket.isClosed())
+        {
+            closedSocket = true;
+            System.err.println(" *** " + TRACE_PREFIX + "datagramSocket.isClosed() unexpectedly, retrying...");
+        }
+        if ((datagramSocket == null) || closedSocket)
+        {
+            try
+            {
+                // The initial value of the SO_BROADCAST socket option is FALSE
+                datagramSocket = new MulticastSocket(getDisPort());
+                ((MulticastSocket) datagramSocket).joinGroup(inetSocket, networkInterface);
+            }
+            catch (IOException ex)
+            {
+                System.err.println(" *** " + TRACE_PREFIX + "Exception in DisThreadedNetworkInterface receive thread: " + ex.getLocalizedMessage());
+            }
+        }
+    }
+  
+    private Runnable receiveThread = () -> {
+
+        int counter = 0;
+
+        // The capacity could go up to MAX_DIS_PDU_SIZE, but this should be good for now
+        // The raw listeners will strip off any extra padding and process what is
+        // required
+        ByteBuffer byteBuffer = ByteBuffer.allocate(MAX_TRANSMISSION_UNIT_SIZE);
+        DatagramPacket packet = new DatagramPacket(byteBuffer.array(), byteBuffer.capacity());
+        Pdu pdu;
+
+        while (!killed) { // keep trying on error
+            
+            // If something trips up with the socket, this thread will attempt to
+            // re-establish for both send/receive threads
+            try {
+                createDatagramSocket (); // ensure socket open, recreate if needed, other thread may occur first
+
+                while (!killed)
+                {
+                    datagramSocket.receive(packet); // blocks here waiting for next DIS pdu to be received on multicast IP and specified port
+                    toRawListeners(packet.getData(), packet.getLength());
+
+                    pdu = pduFactory.createPdu(byteBuffer);
+
+                    if (pdu != null)
+                    {
+                        counter++; // TODO experimental, add to generator as a commented-out diagnostic; consider adding diagnostic mode
+                        if (isVerbose())
+                        {
+                            String message = TRACE_PREFIX + counter + ". received " + pdu.getPduType().toString();
+                            if (isVerboseIncludesTimestamp())
+                                message += " (timestamp " + DisTime.timeStampToString(pdu.getTimestamp());
+                            message +=", size " + pdu.getMarshalledSize() + " bytes)";
+                            System.out.println(message);
+                            System.out.flush();
+                        }
+                        toListeners(pdu);
+                    }
+                    byteBuffer.clear();
+                }
+            } 
+            catch (IOException ex) {
+                System.err.println(TRACE_PREFIX + "Exception in DisThreadedNetworkInterface receive thread: " + ex.getLocalizedMessage());
+                System.err.println(TRACE_PREFIX + "Retrying new socket...");
+            } 
+            finally
+            {
+                if (datagramSocket != null && !datagramSocket.isClosed()) {
+                    try {
+                        ((MulticastSocket)datagramSocket).leaveGroup(inetSocket, networkInterface);
+                    } catch (IOException ex) {
+                        Logger.getLogger(DisThreadedNetworkInterface.class.getName()).log(Level.SEVERE, null, ex);
+                    }
+                    datagramSocket.close();
+                    sleep(100l); // TODO needed?
+                    datagramSocket = null;
+                }
+            }
+//      if (!killed)
+//        sleep(250);
+        }
+    };
+
+    private final Runnable sendThread = () -> {
+
+        Pdu pdu;
+
+        // The capacity could go up to MAX_DIS_PDU_SIZE, but this should be good for now
+        ByteArrayOutputStream baos   = new ByteArrayOutputStream(MAX_TRANSMISSION_UNIT_SIZE);
+        DataOutputStream      dos    = new DataOutputStream(baos);
+        DatagramPacket        packet = new DatagramPacket(baos.toByteArray(), baos.size(), inetSocket);
+
+        while (!killed) { // keep trying on error
+
+            // If something trips up with the socket, this thread will attempt to
+            // re-establish for both send/receive threads
+            try {
+                createDatagramSocket (); // ensure socket open, recreate if needed, other thread may occur first
+
+                while (!killed) {
+                    pdu = pdus2send.take();
+
+                    pdu.marshal(dos);
+                    packet.setData(baos.toByteArray());
+                    datagramSocket.send(packet);
+
+                    dos.flush();  // immediately force pdu write
+                    baos.reset();
+                }
+            } 
+            catch (Exception ex)
+            {
+                System.err.println(TRACE_PREFIX + "Exception in DisThreadedNetworkInterface send thread: " + ex.getLocalizedMessage());
+            }
+        }
+        try {
+            dos.close();
+        } catch (IOException e) {}
+    };
+
+    private void toListeners(Pdu pdu) {
+        if (everyTypeListeners.isEmpty()) {
+            return;
+        }
+
+        if (pdu != null) {
+            everyTypeListeners.forEach(lis -> lis.incomingPdu(pdu));
+
+            if (typeListeners.isEmpty()) {
+                return;
+            }
+
+            List<PduListener> arLis = typeListeners.get(pdu.getPduType());
+            if (arLis != null) {
+                arLis.forEach(lis -> lis.incomingPdu(pdu));
+            }
+        }
+    }
+  
+  private void toRawListeners(byte[] data, int len)
+  {
+    if(rawListeners.isEmpty())
+      return;
+    
+    ByteArrayBufferAndLength bl = new ByteArrayBufferAndLength(data, len);
+    rawListeners.forEach(lis->lis.incomingPdu(bl));
+  }
+
+  /** Terminate the instance */
+  public void kill()
+  {
+    killed = true; // set loop sentinel for threads
+  }
+
+  /** Thread sleep for indicated interval
+   * @param duration milliseconds */
+  private void sleep(long duration)
+  {
+    try {
+      Thread.sleep(duration);
+    }
+    catch (InterruptedException ie) 
+    {
+        System.err.flush();
+        System.err.println ("*** " + getClass().getName() + ".sleep(" + duration + ") failed to sleep");
+        ie.printStackTrace(System.err);
+    }
+  }
+
+    /**
+     * Find proper IPV4 interface
+     *
+     * @return a network interface to use to join a multicast group
+     */
+    public static NetworkInterface findIpv4Interface() {
+        try {
+            Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
+            NetworkInterface nif;
+            Enumeration<InetAddress> addresses;
+            InetAddress addr;
+
+            while (ifaces != null && ifaces.hasMoreElements()) {
+                nif = ifaces.nextElement();
+                if (nif.isUp()) {
+                    addresses = nif.getInetAddresses();
+                    while (addresses.hasMoreElements()) {
+                        addr = addresses.nextElement();
+                        if (addr instanceof Inet4Address && !addr.isLoopbackAddress() && !addr.isLinkLocalAddress()) 
+                        {
+                            System.out.println(TRACE_PREFIX + " Using network interface " + nif.getDisplayName());
+                            return nif;
+                        }
+                    }
+                }
+            }
+        } catch (SocketException ex) {
+            Logger.getLogger(DisThreadedNetworkInterface.class.getName()).log(Level.SEVERE, null, ex);
+        }
+        return null;
+    }
+
+    /**
+     * @return the verbose
+     */
+    public boolean isVerbose()
+    {
+        return verbose;
+    }
+
+    /**
+     * @param verbose the verbose to set
+     */
+    public void setVerbose(boolean verbose)
+    {
+        this.verbose = verbose;
+    }
+
+    /**
+     * @return the verboseIncludesTimestamp value
+     */
+    public boolean isVerboseIncludesTimestamp()
+    {
+        return verboseIncludesTimestamp;
+    }
+
+    /**
+     * @param verboseIncludesTimestamp the value to set
+     */
+    public void setVerboseIncludesTimestamp(boolean verboseIncludesTimestamp)
+    {
+        this.verboseIncludesTimestamp = verboseIncludesTimestamp;
+    }
+
+    /**
+     * @param disPort the disPort value to set
+     */
+    public void setDisPort(int disPort)
+    {
+        this.disPort = disPort;
+    }
+}
diff --git a/src/edu/nps/moves/dis7/utilities/PduFactory.java b/src/edu/nps/moves/dis7/utilities/PduFactory.java
index 290671b3083ee1ad1a70699a81f0f1407f84a798..aca5d57d5b09894b20bbe439b865e062c2b8737b 100644
--- a/src/edu/nps/moves/dis7/utilities/PduFactory.java
+++ b/src/edu/nps/moves/dis7/utilities/PduFactory.java
@@ -7,7 +7,7 @@ package edu.nps.moves.dis7.utilities;
 
 import edu.nps.moves.dis7.pdus.*;
 import edu.nps.moves.dis7.enumerations.*;
-import edu.nps.moves.dis7.enumerations.DISPDUType;
+import edu.nps.moves.dis7.enumerations.DisPduType;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.nio.ByteBuffer;
@@ -1475,7 +1475,7 @@ public class PduFactory
       .setOriginatingSimulationAddress(newSimulationAddress());
     /*
             .setActionCode(DISAttributeActionCode.NO_STATEMENT)
-            .setAttributeRecordPduType(DISPDUType.OTHER)
+            .setAttributeRecordPduType(DisPduType.OTHER)
             .setAttributeRecordProtocolVersion(DISProtocolFamily.OTHER)
             .setMasterAttributeRecordType(VariableRecordTypes.OTHER)
      */
@@ -1504,7 +1504,7 @@ public class PduFactory
    */
   public Pdu createPdu(ByteBuffer byteBuffer)
   {
-    DISPDUType pduType = getTypeFromByteArray(byteBuffer.array());
+    DisPduType pduType = getTypeFromByteArray(byteBuffer.array());
     return createPdu(pduType, byteBuffer);
   }
 
@@ -1515,9 +1515,9 @@ public class PduFactory
    * @param ba byte array
    * @return the type
    */
-  private DISPDUType getTypeFromByteArray(byte[] ba)
+  private DisPduType getTypeFromByteArray(byte[] ba)
   {
-    return DISPDUType.getEnumForValue(Byte.toUnsignedInt(ba[2])); // 3rd byte
+    return DisPduType.getEnumForValue(Byte.toUnsignedInt(ba[2])); // 3rd byte
   }
   
   /**
@@ -1525,12 +1525,12 @@ public class PduFactory
    * @param pduType PDU type to create
    * @return the empty pdu
    */
-  public Pdu createPdu(DISPDUType pduType)
+  public Pdu createPdu(DisPduType pduType)
   {
     return createPdu(pduType, null);
   }
   
-  private Pdu createPdu(DISPDUType pduType, ByteBuffer byteBuffer)
+  private Pdu createPdu(DisPduType pduType, ByteBuffer byteBuffer)
   {
     Pdu aPdu = null;
     switch (pduType) {
diff --git a/src/edu/nps/moves/dis7/utilities/stream/PduPlayer.java b/src/edu/nps/moves/dis7/utilities/stream/PduPlayer.java
index 3f507bd770bb2662e4b6fb3674b6414e259c1de8..8df7e3a27685841002de7cbf2b42813a8bea64a9 100644
--- a/src/edu/nps/moves/dis7/utilities/stream/PduPlayer.java
+++ b/src/edu/nps/moves/dis7/utilities/stream/PduPlayer.java
@@ -5,7 +5,7 @@
 package edu.nps.moves.dis7.utilities.stream;
 
 import com.google.common.primitives.Longs;
-import edu.nps.moves.dis7.enumerations.DISPDUType;
+import edu.nps.moves.dis7.enumerations.DisPduType;
 
 import java.io.*;
 import java.net.DatagramPacket;
@@ -104,7 +104,7 @@ public class PduPlayer {
             
             InetAddress addr = null;
             DatagramPacket datagramPacket;
-            DISPDUType type;
+            DisPduType type;
             String tempString;
             String[] sa = null, splitString;
             String REGEX;
@@ -248,7 +248,7 @@ public class PduPlayer {
                                 if (netSend) {
                                     datagramPacket = new DatagramPacket(buffer, buffer.length, addr, port);
                                     datagramSocket.send(datagramPacket);
-                                    type = DISPDUType.getEnumForValue(Byte.toUnsignedInt(buffer[2])); // 3rd byte
+                                    type = DisPduType.getEnumForValue(Byte.toUnsignedInt(buffer[2])); // 3rd byte
                                     System.out.println("Sent PDU: " + type);
                                 }
                                 break;
@@ -308,7 +308,7 @@ public class PduPlayer {
                                     globalByteBufferForX3dInterPolators = bufferShort.clone();
                                     x3dInterpolators.addPointsToMap(globalByteBufferForX3dInterPolators); // gets cloned again
                                     x3dLineSet.addPointsToMap(globalByteBufferForX3dInterPolators); // gets cloned again
-                                    type = DISPDUType.getEnumForValue(Byte.toUnsignedInt(bufferShort[2])); // 3rd byte
+                                    type = DisPduType.getEnumForValue(Byte.toUnsignedInt(bufferShort[2])); // 3rd byte
                                     System.out.println("Sent PDU: " + type);
                                 }
                                 break;
diff --git a/src/edu/nps/moves/dis7/utilities/stream/PduRecorder.java b/src/edu/nps/moves/dis7/utilities/stream/PduRecorder.java
index a688f0c59e9214dc01c0c30180a342d7dc5f28ad..b7c19c16bbc996f42fba150884cdcb3f337e512e 100644
--- a/src/edu/nps/moves/dis7/utilities/stream/PduRecorder.java
+++ b/src/edu/nps/moves/dis7/utilities/stream/PduRecorder.java
@@ -2,7 +2,7 @@ package edu.nps.moves.dis7.utilities.stream;
 
 import com.google.common.primitives.Longs;
 
-import edu.nps.moves.dis7.enumerations.DISPDUType;
+import edu.nps.moves.dis7.enumerations.DisPduType;
 import edu.nps.moves.dis7.utilities.DisThreadedNetworkInterface;
 import edu.nps.moves.dis7.utilities.PduFactory;
 
@@ -176,7 +176,7 @@ public class PduRecorder implements PduReceiver
     //System.out.println("wrote time "+(packetRcvNanoTime - startNanoTime));
 
     byte[] buffsized = Arrays.copyOf(newBuffer, newLength);
-    DISPDUType pduType;
+    DisPduType pduType;
     
     switch (pduLogEncoding)
     {
@@ -192,7 +192,7 @@ public class PduRecorder implements PduReceiver
             sb.append(',');
             sb.append(Arrays.toString(buffsized).replace(" ", ""));
             sb.append(" # ");
-            pduType = DISPDUType.getEnumForValue(Byte.toUnsignedInt(buffsized[2])); // 3rd byte
+            pduType = DisPduType.getEnumForValue(Byte.toUnsignedInt(buffsized[2])); // 3rd byte
             sb.append(pduType);
             break;
         
@@ -336,10 +336,10 @@ public class PduRecorder implements PduReceiver
     }
     System.out.println("dis7.utilities.stream.PduRecorder pduRecorder created... isRunning()=" + pduRecorder.isRunning());
      
-    DISPDUType allPDUTypesArray[] = DISPDUType.values();
+    DisPduType allPDUTypesArray[] = DisPduType.values();
     System.out.println("dis7.utilities.stream.PduRecorder allPDUTypesArray created, length=" + allPDUTypesArray.length + " ...");
     Arrays.stream(allPDUTypesArray).forEach(pduTypeValue-> {
-      if(pduTypeValue != DISPDUType.OTHER) 
+      if(pduTypeValue != DisPduType.OTHER) 
       {
         try {
             pduRecorder.getDisThreadedNetIF().send(factory.createPdu(pduTypeValue));
diff --git a/src/edu/nps/moves/dis7/utilities/stream/X3dCreateInterpolators.java b/src/edu/nps/moves/dis7/utilities/stream/X3dCreateInterpolators.java
index b1a3e051d716804adc2dbc9297bfd63f7ca28b67..71ef45cab69b95c3ca8b1aa35ab67faa93e80ab3 100644
--- a/src/edu/nps/moves/dis7/utilities/stream/X3dCreateInterpolators.java
+++ b/src/edu/nps/moves/dis7/utilities/stream/X3dCreateInterpolators.java
@@ -1,277 +1,277 @@
-package edu.nps.moves.dis7.utilities.stream;
-
-import edu.nps.moves.dis7.pdus.EntityStatePdu;
-import edu.nps.moves.dis7.pdus.Pdu;
-import edu.nps.moves.dis7.enumerations.DISPDUType;
-import edu.nps.moves.dis7.utilities.PduFactory;
-import java.nio.ByteBuffer;
-import java.text.NumberFormat;
-import java.util.LinkedHashMap;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- *
- * @author Tobias Brennenstuhl @ NPS
- */
-public class X3dCreateInterpolators {
-
-    private byte[] bufferShort;
-
-    // -------------------- Begin Variables for Position Interpolator
-    private Boolean firstTimeStamp = true;
-    private int firstLocalTimeStamp = 0;
-
-    private double firstLocalX = 0;
-    private double firstLocalY = 0;
-    private double firstLocalZ = 0;
-
-    private Map<Double, X3dCoordinates> testMap = new LinkedHashMap<>();
-
-    //Setting up a NumberFormatter for limitting the decimal count to 3
-    private NumberFormat coordinateNumberFormat = NumberFormat.getInstance(new Locale("en", "US"));
-
-    // -------------------- End Variables for Position Interpolator
-
-    /** Default Constructor */
-    public X3dCreateInterpolators() {
-
-        //3 significant digits equals milimeter position accuracy and 0.001 radians = 0.0572963266634555‬ degrees
-        coordinateNumberFormat.setMaximumFractionDigits(3);
-
-    }
-
-    public void addPointsToMap(byte[] localBufferShort) {
-
-        this.bufferShort = localBufferShort.clone();
-
-        if (bufferShort[2] == 1) {
-
-            //PDU Factory
-            PduFactory pduFactory = new PduFactory();
-            Pdu localPdu = pduFactory.createPdu(bufferShort);
-
-            // ToDO figure out how to do this! makeEntityStatePDU
-            EntityStatePdu localEspdu = pduFactory.makeEntityStatePdu();
-            //Put all the data we need into the localEspdu
-            ByteBuffer espduByteBuffer = ByteBuffer.wrap(bufferShort);
-            try {
-                localEspdu.unmarshal(espduByteBuffer);
-            } catch (Exception ex) {
-                Logger.getLogger(X3dCreateInterpolators.class.getName()).log(Level.SEVERE, null, ex);
-            }
-
-            double localTimeStamp;
-            double localX;
-            double localY;
-            double localZ;
-
-            double localPhi;
-            double localPsi;
-            double localTheta;
-
-            //Store the first timestamp to subtract it from all others
-            //Same with X,Y,Z to create a local coordiante system
-            if (firstTimeStamp) {
-
-                firstLocalTimeStamp = localPdu.getTimestamp();
-                firstLocalX = localEspdu.getEntityLocation().getX();
-                firstLocalY = localEspdu.getEntityLocation().getZ();
-                firstLocalZ = -1 * localEspdu.getEntityLocation().getY();
-
-                firstTimeStamp = false;
-            }
-
-            localTimeStamp = localPdu.getTimestamp();
-            localX = localEspdu.getEntityLocation().getX();
-            localY = localEspdu.getEntityLocation().getZ();
-            localZ = -1 * localEspdu.getEntityLocation().getY();
-            localPhi = localEspdu.getEntityOrientation().getPhi();
-            localPsi = localEspdu.getEntityOrientation().getPsi();
-            localTheta = localEspdu.getEntityOrientation().getTheta();
-
-            localTimeStamp = localTimeStamp - firstLocalTimeStamp;
-            localX = localX - firstLocalX;
-            localY = localY - firstLocalY;
-            localZ = localZ - firstLocalZ;
-
-            //Divide TimeStamp by 1,300,000 to get something close to a second per Unit.
-            //According to the DIS standard one tick is 3600/(2^31) seconds ~ 1.6764 µs
-            //1,100,000 was derived from a stream that is 83 seconds long. The number was adjusted to get a timesensor with 83 seconds
-            //ToDo find the real conversion between TimeStampDelta and seconds
-            localTimeStamp = localTimeStamp / 1100000;
-
-            //Only add to stream if it is an ESPDU
-            //ToDo: Add support for multiple Entities
-            if ((localPdu.getPduType() != null) && (localPdu.getPduType() == DISPDUType.ENTITY_STATE))
-                testMap.put(localTimeStamp, new X3dCoordinates(localX, localY, localZ, localPhi, localPsi, localTheta));
-        }
-    }
-
-    public void makeX3dInterpolator()
-    {
-        //Compression of the testMap.
-        //Remove all collinear points.
-        X3dSlidingWindowCompression slidingWindowCompression = new X3dSlidingWindowCompression(testMap);
-
-        //To turn of the compression just comment the next line out and the very next in.
-        Map<Double, X3dCoordinates> returnMap = slidingWindowCompression.doSlidingWindow();
-        //returnMap.putAll(testMap);
-
-        //Writing all values from the KeyMap to a proper Position Interpolator String
-        System.out.println("Writing Position and Rotation Interpolator");
-        Set<Double> keys = returnMap.keySet();
-        //Set<Double> keys = tempKeyKeyValueSetPositionInterPolator.keySet();
-        String positionKey = "key = '";
-        String positionKeyValue = "keyValue = '";
-        String positionInterpolatorToCopy = "<PositionInterpolator DEF='EntityPosition' ";
-
-        String orientationKeyX = "key = '";
-        String orientationKeyValueX = "keyValue = '";
-        String orientationInterpolatorToCopyX = "<OrientationInterpolator DEF='EntityOrientationX' ";
-
-        String orientationKeyY = "key = '";
-        String orientationKeyValueY = "keyValue = '";
-        String orientationInterpolatorToCopyY = "<OrientationInterpolator DEF='EntityOrientationY' ";
-
-        String orientationKeyZ = "key = '";
-        String orientationKeyValueZ = "keyValue = '";
-        String orientationInterpolatorToCopyZ = "<OrientationInterpolator DEF='EntityOrientationZ' ";
-
-        //Find highest time to do the normalization
-        double lastTimeStamp = 0;
-
-        for (Double k : keys) {
-
-            if (k > lastTimeStamp)
-                lastTimeStamp = k;
-        }
-
-        //Normalize all times in the set
-        Map<Double, String> keyKeyValueSetPositionInterpolator = new LinkedHashMap<>();
-
-        Map<Double, String> keyKeyValueSetOrientationInterpolatorX = new LinkedHashMap<>();
-        Map<Double, String> keyKeyValueSetOrientationInterpolatorY = new LinkedHashMap<>();
-        Map<Double, String> keyKeyValueSetOrientationInterpolatorZ = new LinkedHashMap<>();
-        
-        double tempX;
-        double tempY;
-        double tempZ ;
-
-        double tempPhi;
-        double tempPsi;
-        double tempTheta;
-        
-        String localCoordinateString;
-        String localOrientationStringX;
-        String localOrientationStringY;
-        String localOrientationStringZ;
-
-        for (Double k : keys) {
-
-            tempX = returnMap.get(k).getX();
-            tempY = returnMap.get(k).getY();
-            tempZ = returnMap.get(k).getZ();
-
-            tempPhi = returnMap.get(k).getPhi() / 6.28;
-            tempPsi = returnMap.get(k).getPsi() / 6.28;
-            tempTheta = returnMap.get(k).getTheta() / 6.28;
-
-            localCoordinateString = " " + coordinateNumberFormat.format(tempX) + " " + coordinateNumberFormat.format(tempY) + " " + coordinateNumberFormat.format(tempZ);
-            localOrientationStringX = " 1 0 0 " + coordinateNumberFormat.format(tempPhi);
-            localOrientationStringY = " 0 1 0 " + coordinateNumberFormat.format(tempTheta);
-            localOrientationStringZ = " 0 0 1 " + coordinateNumberFormat.format(tempPsi);
-
-            keyKeyValueSetPositionInterpolator.put(k / lastTimeStamp, localCoordinateString);
-            keyKeyValueSetOrientationInterpolatorX.put(k / lastTimeStamp, localOrientationStringX);
-            keyKeyValueSetOrientationInterpolatorY.put(k / lastTimeStamp, localOrientationStringY);
-            keyKeyValueSetOrientationInterpolatorZ.put(k / lastTimeStamp, localOrientationStringZ);
-
-        }
-
-        keys = keyKeyValueSetPositionInterpolator.keySet();
-
-        //Setting up the timeSensor
-        //Only one timeSensor for both interpolators is needed
-        String timeSensor = "<TimeSensor DEF='PduStreamClock' cycleInterval='";
-
-        timeSensor += lastTimeStamp;
-
-        timeSensor += "' loop = 'true'/>";
-
-        //Printing the timeSensor to the console
-        System.out.println(timeSensor);
-
-        //Setting up PositionInterpolator and OrientationInterpolator
-        for (Double k : keys) {
-            //System.out.println("Time: " + k + " Position (x,y,z) " + keyKeyValueSetPositionInterpolator.get(k));
-
-            //PositionInterpolator
-            positionKey += coordinateNumberFormat.format(k) + " ";
-            positionKeyValue += keyKeyValueSetPositionInterpolator.get(k) + " ";
-
-            //OrientationInterpolator for X (phi)
-            orientationKeyX += coordinateNumberFormat.format(k) + " ";
-            orientationKeyValueX += keyKeyValueSetOrientationInterpolatorX.get(k) + " ";
-
-            //OrientationInterpolator for Y (theta)
-            orientationKeyY += coordinateNumberFormat.format(k) + " ";
-            orientationKeyValueY += keyKeyValueSetOrientationInterpolatorY.get(k) + " ";
-
-            //OrientationInterpolator for Z (psi)
-            orientationKeyZ += coordinateNumberFormat.format(k) + " ";
-            orientationKeyValueZ += keyKeyValueSetOrientationInterpolatorZ.get(k) + " ";
-
-        }
-        positionKey += "' ";
-        positionKeyValue += "' ";
-
-        orientationKeyX += "' ";
-        orientationKeyValueX += "' ";
-
-        orientationKeyY += "' ";
-        orientationKeyValueY += "' ";
-
-        orientationKeyZ += "' ";
-        orientationKeyValueZ += "' ";
-
-        //PositionInterpolator
-        positionInterpolatorToCopy += positionKey + "\n";
-        positionInterpolatorToCopy += positionKeyValue;
-        positionInterpolatorToCopy += "/>";
-
-        //PositionInterpolator for X
-        orientationInterpolatorToCopyX += orientationKeyX + "\n";
-        orientationInterpolatorToCopyX += orientationKeyValueX;
-        orientationInterpolatorToCopyX += "/>";
-
-        //PositionInterpolator for Y
-        orientationInterpolatorToCopyY += orientationKeyY + "\n";
-        orientationInterpolatorToCopyY += orientationKeyValueY;
-        orientationInterpolatorToCopyY += "/>";
-
-        //PositionInterpolator for Z
-        orientationInterpolatorToCopyZ += orientationKeyY + "\n";
-        orientationInterpolatorToCopyZ += orientationKeyValueZ;
-        orientationInterpolatorToCopyZ += "/>";
-
-        //Printing PositionInterpolator to the console
-        System.out.println(positionInterpolatorToCopy);
-
-        //First Rotation must be around z axis by psi
-        //Printing OrientationInterpolator for X to the console
-        System.out.println(orientationInterpolatorToCopyZ);
-
-        //Second Rotation must be around resulting y (y') axis by theta
-        //Printing OrientationInterpolator for Y to the console
-        System.out.println(orientationInterpolatorToCopyY);
-
-        //last rotation must be around resulting x (x') axis by phi
-        //Printing OrientationInterpolator for Z to the console
-        System.out.println(orientationInterpolatorToCopyX);
-    }
-
-}
+package edu.nps.moves.dis7.utilities.stream;
+
+import edu.nps.moves.dis7.pdus.EntityStatePdu;
+import edu.nps.moves.dis7.pdus.Pdu;
+import edu.nps.moves.dis7.enumerations.DisPduType;
+import edu.nps.moves.dis7.utilities.PduFactory;
+import java.nio.ByteBuffer;
+import java.text.NumberFormat;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author Tobias Brennenstuhl @ NPS
+ */
+public class X3dCreateInterpolators {
+
+    private byte[] bufferShort;
+
+    // -------------------- Begin Variables for Position Interpolator
+    private Boolean firstTimeStamp = true;
+    private int firstLocalTimeStamp = 0;
+
+    private double firstLocalX = 0;
+    private double firstLocalY = 0;
+    private double firstLocalZ = 0;
+
+    private Map<Double, X3dCoordinates> testMap = new LinkedHashMap<>();
+
+    //Setting up a NumberFormatter for limitting the decimal count to 3
+    private NumberFormat coordinateNumberFormat = NumberFormat.getInstance(new Locale("en", "US"));
+
+    // -------------------- End Variables for Position Interpolator
+
+    /** Default Constructor */
+    public X3dCreateInterpolators() {
+
+        //3 significant digits equals milimeter position accuracy and 0.001 radians = 0.0572963266634555‬ degrees
+        coordinateNumberFormat.setMaximumFractionDigits(3);
+
+    }
+
+    public void addPointsToMap(byte[] localBufferShort) {
+
+        this.bufferShort = localBufferShort.clone();
+
+        if (bufferShort[2] == 1) {
+
+            //PDU Factory
+            PduFactory pduFactory = new PduFactory();
+            Pdu localPdu = pduFactory.createPdu(bufferShort);
+
+            // ToDO figure out how to do this! makeEntityStatePDU
+            EntityStatePdu localEspdu = pduFactory.makeEntityStatePdu();
+            //Put all the data we need into the localEspdu
+            ByteBuffer espduByteBuffer = ByteBuffer.wrap(bufferShort);
+            try {
+                localEspdu.unmarshal(espduByteBuffer);
+            } catch (Exception ex) {
+                Logger.getLogger(X3dCreateInterpolators.class.getName()).log(Level.SEVERE, null, ex);
+            }
+
+            double localTimeStamp;
+            double localX;
+            double localY;
+            double localZ;
+
+            double localPhi;
+            double localPsi;
+            double localTheta;
+
+            //Store the first timestamp to subtract it from all others
+            //Same with X,Y,Z to create a local coordiante system
+            if (firstTimeStamp) {
+
+                firstLocalTimeStamp = localPdu.getTimestamp();
+                firstLocalX = localEspdu.getEntityLocation().getX();
+                firstLocalY = localEspdu.getEntityLocation().getZ();
+                firstLocalZ = -1 * localEspdu.getEntityLocation().getY();
+
+                firstTimeStamp = false;
+            }
+
+            localTimeStamp = localPdu.getTimestamp();
+            localX = localEspdu.getEntityLocation().getX();
+            localY = localEspdu.getEntityLocation().getZ();
+            localZ = -1 * localEspdu.getEntityLocation().getY();
+            localPhi = localEspdu.getEntityOrientation().getPhi();
+            localPsi = localEspdu.getEntityOrientation().getPsi();
+            localTheta = localEspdu.getEntityOrientation().getTheta();
+
+            localTimeStamp = localTimeStamp - firstLocalTimeStamp;
+            localX = localX - firstLocalX;
+            localY = localY - firstLocalY;
+            localZ = localZ - firstLocalZ;
+
+            //Divide TimeStamp by 1,300,000 to get something close to a second per Unit.
+            //According to the DIS standard one tick is 3600/(2^31) seconds ~ 1.6764 µs
+            //1,100,000 was derived from a stream that is 83 seconds long. The number was adjusted to get a timesensor with 83 seconds
+            //ToDo find the real conversion between TimeStampDelta and seconds
+            localTimeStamp = localTimeStamp / 1100000;
+
+            //Only add to stream if it is an ESPDU
+            //ToDo: Add support for multiple Entities
+            if ((localPdu.getPduType() != null) && (localPdu.getPduType() == DisPduType.ENTITY_STATE))
+                testMap.put(localTimeStamp, new X3dCoordinates(localX, localY, localZ, localPhi, localPsi, localTheta));
+        }
+    }
+
+    public void makeX3dInterpolator()
+    {
+        //Compression of the testMap.
+        //Remove all collinear points.
+        X3dSlidingWindowCompression slidingWindowCompression = new X3dSlidingWindowCompression(testMap);
+
+        //To turn of the compression just comment the next line out and the very next in.
+        Map<Double, X3dCoordinates> returnMap = slidingWindowCompression.doSlidingWindow();
+        //returnMap.putAll(testMap);
+
+        //Writing all values from the KeyMap to a proper Position Interpolator String
+        System.out.println("Writing Position and Rotation Interpolator");
+        Set<Double> keys = returnMap.keySet();
+        //Set<Double> keys = tempKeyKeyValueSetPositionInterPolator.keySet();
+        String positionKey = "key = '";
+        String positionKeyValue = "keyValue = '";
+        String positionInterpolatorToCopy = "<PositionInterpolator DEF='EntityPosition' ";
+
+        String orientationKeyX = "key = '";
+        String orientationKeyValueX = "keyValue = '";
+        String orientationInterpolatorToCopyX = "<OrientationInterpolator DEF='EntityOrientationX' ";
+
+        String orientationKeyY = "key = '";
+        String orientationKeyValueY = "keyValue = '";
+        String orientationInterpolatorToCopyY = "<OrientationInterpolator DEF='EntityOrientationY' ";
+
+        String orientationKeyZ = "key = '";
+        String orientationKeyValueZ = "keyValue = '";
+        String orientationInterpolatorToCopyZ = "<OrientationInterpolator DEF='EntityOrientationZ' ";
+
+        //Find highest time to do the normalization
+        double lastTimeStamp = 0;
+
+        for (Double k : keys) {
+
+            if (k > lastTimeStamp)
+                lastTimeStamp = k;
+        }
+
+        //Normalize all times in the set
+        Map<Double, String> keyKeyValueSetPositionInterpolator = new LinkedHashMap<>();
+
+        Map<Double, String> keyKeyValueSetOrientationInterpolatorX = new LinkedHashMap<>();
+        Map<Double, String> keyKeyValueSetOrientationInterpolatorY = new LinkedHashMap<>();
+        Map<Double, String> keyKeyValueSetOrientationInterpolatorZ = new LinkedHashMap<>();
+        
+        double tempX;
+        double tempY;
+        double tempZ ;
+
+        double tempPhi;
+        double tempPsi;
+        double tempTheta;
+        
+        String localCoordinateString;
+        String localOrientationStringX;
+        String localOrientationStringY;
+        String localOrientationStringZ;
+
+        for (Double k : keys) {
+
+            tempX = returnMap.get(k).getX();
+            tempY = returnMap.get(k).getY();
+            tempZ = returnMap.get(k).getZ();
+
+            tempPhi = returnMap.get(k).getPhi() / 6.28;
+            tempPsi = returnMap.get(k).getPsi() / 6.28;
+            tempTheta = returnMap.get(k).getTheta() / 6.28;
+
+            localCoordinateString = " " + coordinateNumberFormat.format(tempX) + " " + coordinateNumberFormat.format(tempY) + " " + coordinateNumberFormat.format(tempZ);
+            localOrientationStringX = " 1 0 0 " + coordinateNumberFormat.format(tempPhi);
+            localOrientationStringY = " 0 1 0 " + coordinateNumberFormat.format(tempTheta);
+            localOrientationStringZ = " 0 0 1 " + coordinateNumberFormat.format(tempPsi);
+
+            keyKeyValueSetPositionInterpolator.put(k / lastTimeStamp, localCoordinateString);
+            keyKeyValueSetOrientationInterpolatorX.put(k / lastTimeStamp, localOrientationStringX);
+            keyKeyValueSetOrientationInterpolatorY.put(k / lastTimeStamp, localOrientationStringY);
+            keyKeyValueSetOrientationInterpolatorZ.put(k / lastTimeStamp, localOrientationStringZ);
+
+        }
+
+        keys = keyKeyValueSetPositionInterpolator.keySet();
+
+        //Setting up the timeSensor
+        //Only one timeSensor for both interpolators is needed
+        String timeSensor = "<TimeSensor DEF='PduStreamClock' cycleInterval='";
+
+        timeSensor += lastTimeStamp;
+
+        timeSensor += "' loop = 'true'/>";
+
+        //Printing the timeSensor to the console
+        System.out.println(timeSensor);
+
+        //Setting up PositionInterpolator and OrientationInterpolator
+        for (Double k : keys) {
+            //System.out.println("Time: " + k + " Position (x,y,z) " + keyKeyValueSetPositionInterpolator.get(k));
+
+            //PositionInterpolator
+            positionKey += coordinateNumberFormat.format(k) + " ";
+            positionKeyValue += keyKeyValueSetPositionInterpolator.get(k) + " ";
+
+            //OrientationInterpolator for X (phi)
+            orientationKeyX += coordinateNumberFormat.format(k) + " ";
+            orientationKeyValueX += keyKeyValueSetOrientationInterpolatorX.get(k) + " ";
+
+            //OrientationInterpolator for Y (theta)
+            orientationKeyY += coordinateNumberFormat.format(k) + " ";
+            orientationKeyValueY += keyKeyValueSetOrientationInterpolatorY.get(k) + " ";
+
+            //OrientationInterpolator for Z (psi)
+            orientationKeyZ += coordinateNumberFormat.format(k) + " ";
+            orientationKeyValueZ += keyKeyValueSetOrientationInterpolatorZ.get(k) + " ";
+
+        }
+        positionKey += "' ";
+        positionKeyValue += "' ";
+
+        orientationKeyX += "' ";
+        orientationKeyValueX += "' ";
+
+        orientationKeyY += "' ";
+        orientationKeyValueY += "' ";
+
+        orientationKeyZ += "' ";
+        orientationKeyValueZ += "' ";
+
+        //PositionInterpolator
+        positionInterpolatorToCopy += positionKey + "\n";
+        positionInterpolatorToCopy += positionKeyValue;
+        positionInterpolatorToCopy += "/>";
+
+        //PositionInterpolator for X
+        orientationInterpolatorToCopyX += orientationKeyX + "\n";
+        orientationInterpolatorToCopyX += orientationKeyValueX;
+        orientationInterpolatorToCopyX += "/>";
+
+        //PositionInterpolator for Y
+        orientationInterpolatorToCopyY += orientationKeyY + "\n";
+        orientationInterpolatorToCopyY += orientationKeyValueY;
+        orientationInterpolatorToCopyY += "/>";
+
+        //PositionInterpolator for Z
+        orientationInterpolatorToCopyZ += orientationKeyY + "\n";
+        orientationInterpolatorToCopyZ += orientationKeyValueZ;
+        orientationInterpolatorToCopyZ += "/>";
+
+        //Printing PositionInterpolator to the console
+        System.out.println(positionInterpolatorToCopy);
+
+        //First Rotation must be around z axis by psi
+        //Printing OrientationInterpolator for X to the console
+        System.out.println(orientationInterpolatorToCopyZ);
+
+        //Second Rotation must be around resulting y (y') axis by theta
+        //Printing OrientationInterpolator for Y to the console
+        System.out.println(orientationInterpolatorToCopyY);
+
+        //last rotation must be around resulting x (x') axis by phi
+        //Printing OrientationInterpolator for Z to the console
+        System.out.println(orientationInterpolatorToCopyX);
+    }
+
+}
diff --git a/src/edu/nps/moves/dis7/utilities/stream/X3dCreateLineSet.java b/src/edu/nps/moves/dis7/utilities/stream/X3dCreateLineSet.java
index 8176a11429126d95aca80259ba6933abd353c127..10bfaa76944f0448316c2dc91b6a9132ebd7a032 100644
--- a/src/edu/nps/moves/dis7/utilities/stream/X3dCreateLineSet.java
+++ b/src/edu/nps/moves/dis7/utilities/stream/X3dCreateLineSet.java
@@ -1,171 +1,171 @@
-package edu.nps.moves.dis7.utilities.stream;
-
-import edu.nps.moves.dis7.pdus.EntityStatePdu;
-import edu.nps.moves.dis7.pdus.Pdu;
-import edu.nps.moves.dis7.enumerations.DISPDUType;
-import edu.nps.moves.dis7.utilities.PduFactory;
-import java.nio.ByteBuffer;
-import java.text.NumberFormat;
-import java.util.LinkedHashMap;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- *
- * @author Tobias Brennenstuhl @ NPS
- */
-public class X3dCreateLineSet {
-
-    private byte[] bufferShort;
-
-    // -------------------- Begin Variables for Position Interpolator
-    private Boolean firstTimeStamp = true;
-    private int firstLocalTimeStamp = 0;
-
-    private double firstLocalX = 0;
-    private double firstLocalY = 0;
-    private double firstLocalZ = 0;
-
-    private Map<Double, X3dCoordinates> testMap = new LinkedHashMap<>();
-
-    //Setting up a NumberFormatter for limitting the decimal count to 3
-    private NumberFormat coordinateNumberFormat = NumberFormat.getInstance(new Locale("en", "US"));
-
-    // -------------------- End Variables for Position Interpolator
-
-    /** Constructor */
-    public X3dCreateLineSet()
-    {
-        //3 significant digits equals milimeter position accuracy and 0.001 radians = 0.0572963266634555‬ degrees
-        coordinateNumberFormat.setMaximumFractionDigits(3);
-    }
-
-    public void addPointsToMap(byte[] localBufferShort)
-    {
-        this.bufferShort = localBufferShort.clone();
-
-        if (bufferShort[2] == 1) {
-
-            //PDU Factory
-            PduFactory pduFactory = new PduFactory();
-            Pdu localPdu = pduFactory.createPdu(bufferShort);
-
-            // ToDO figure out how to do this! makeEntityStatePDU
-            EntityStatePdu localEspdu = pduFactory.makeEntityStatePdu();
-            //Put all the data we need into the localEspdu
-            ByteBuffer espduByteBuffer = ByteBuffer.wrap(bufferShort);
-            try {
-                localEspdu.unmarshal(espduByteBuffer);
-            } catch (Exception ex) {
-                Logger.getLogger(X3dCreateLineSet.class.getName()).log(Level.SEVERE, null, ex);
-            }
-
-            double localTimeStamp;
-            double localX;
-            double localY;
-            double localZ;
-
-            //TimeStamps for a lineSet is not needed but copied from X3DInterpolators to use them as key for the hashmap
-            // and the standard compression class can be used
-            //Store the first timestamp to subtract it from all others
-            //Same with X,Y,Z to create a local coordiante system
-            if (firstTimeStamp) {
-
-                firstLocalTimeStamp = localPdu.getTimestamp();
-                firstLocalX = localEspdu.getEntityLocation().getX();
-                firstLocalY = localEspdu.getEntityLocation().getZ();
-                firstLocalZ = -1 * localEspdu.getEntityLocation().getY();
-
-                firstTimeStamp = false;
-            }
-
-            localTimeStamp = localPdu.getTimestamp();
-            localX = localEspdu.getEntityLocation().getX();
-            localY = localEspdu.getEntityLocation().getZ();
-            localZ = -1 * localEspdu.getEntityLocation().getY();
-
-            //Debug for printing X,Y,Z
-            //System.out.println(localX + " " + localY + " " + localZ);
-            localTimeStamp = localTimeStamp - firstLocalTimeStamp;
-            localX = localX - firstLocalX;
-            localY = localY - firstLocalY;
-            localZ = localZ - firstLocalZ;
-
-            //Divide TimeStamp by 1,300,000 to get something close to a second per Unit.
-            //According to the DIS standard one tick is 3600/(2^31) seconds ~ 1.6764 µs
-            //1,300,000 was derived from a stream that is 61 seconds long. The number was adjusted to get a timesensor with 61 seconds
-            //ToDo find the real conversion between TimeStampDelta and seconds
-            localTimeStamp = localTimeStamp / 1300000;
-
-            //Only add to stream if it is an ESPDU
-            //ToDo: Add support for multiple Entities
-            if ((localPdu.getPduType() != null) && (localPdu.getPduType() == DISPDUType.ENTITY_STATE))
-                testMap.put(localTimeStamp, new X3dCoordinates(localX, localY, localZ, 0.0, 0.0, 0.0));
-        }
-    }
-
-    public void makeX3dLineSet() {
-
-        //Compression of the testMap.
-        //Remove all collinear points.
-        X3dSlidingWindowCompression regression = new X3dSlidingWindowCompression(testMap);
-
-        //To turn of the compression just comment the next line out and the very next in.
-        Map<Double, X3dCoordinates> returnMap = regression.doSlidingWindow();
-        //returnMap.putAll(testMap);
-
-        //Writing all values from the KeyMap to a proper Position Interpolator String
-        System.out.println("Writing X3D LineSet");
-        Set<Double> keys = returnMap.keySet();
-        String lineSetPoints = "";
-        String lineSet = "<LineSet vertexCount='" + returnMap.size() + "'> \n <Coordinate point='";
-
-        //Find highest time to do the normalization
-        double lastTimeStamp = 0;
-
-        for (Double k : keys) {
-
-            if (k > lastTimeStamp)
-                lastTimeStamp = k;
-        }
-
-        //Normalize all times in the set
-        Map<Double, String> keyKeyValueSetPositionInterpolator = new LinkedHashMap<>();
-
-        for (Double k : keys) {
-
-            String localCoordinateString;
-
-            double tempX = returnMap.get(k).getX();
-            double tempY = returnMap.get(k).getY();
-            double tempZ = returnMap.get(k).getZ();
-
-            localCoordinateString = " " + coordinateNumberFormat.format(tempX) + " " + coordinateNumberFormat.format(tempY) + " " + coordinateNumberFormat.format(tempZ);
-
-            keyKeyValueSetPositionInterpolator.put(k / lastTimeStamp, localCoordinateString);
-
-        }
-
-        keys = keyKeyValueSetPositionInterpolator.keySet();
-
-     
-
-        //Setting up PositionInterpolator and OrientationInterpolator
-        for (Double k : keys)
-            lineSetPoints += keyKeyValueSetPositionInterpolator.get(k) + " ";
-
-        lineSetPoints += "' ";
-
-        //PositionInterpolator
-
-        lineSet += lineSetPoints;
-        lineSet += "/>\n</LineSet> \n";
-
-        //Printing PositionInterpolator to the console
-        System.out.println(lineSet);
-    }
-
-}
+package edu.nps.moves.dis7.utilities.stream;
+
+import edu.nps.moves.dis7.pdus.EntityStatePdu;
+import edu.nps.moves.dis7.pdus.Pdu;
+import edu.nps.moves.dis7.enumerations.DisPduType;
+import edu.nps.moves.dis7.utilities.PduFactory;
+import java.nio.ByteBuffer;
+import java.text.NumberFormat;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author Tobias Brennenstuhl @ NPS
+ */
+public class X3dCreateLineSet {
+
+    private byte[] bufferShort;
+
+    // -------------------- Begin Variables for Position Interpolator
+    private Boolean firstTimeStamp = true;
+    private int firstLocalTimeStamp = 0;
+
+    private double firstLocalX = 0;
+    private double firstLocalY = 0;
+    private double firstLocalZ = 0;
+
+    private Map<Double, X3dCoordinates> testMap = new LinkedHashMap<>();
+
+    //Setting up a NumberFormatter for limitting the decimal count to 3
+    private NumberFormat coordinateNumberFormat = NumberFormat.getInstance(new Locale("en", "US"));
+
+    // -------------------- End Variables for Position Interpolator
+
+    /** Constructor */
+    public X3dCreateLineSet()
+    {
+        //3 significant digits equals milimeter position accuracy and 0.001 radians = 0.0572963266634555‬ degrees
+        coordinateNumberFormat.setMaximumFractionDigits(3);
+    }
+
+    public void addPointsToMap(byte[] localBufferShort)
+    {
+        this.bufferShort = localBufferShort.clone();
+
+        if (bufferShort[2] == 1) {
+
+            //PDU Factory
+            PduFactory pduFactory = new PduFactory();
+            Pdu localPdu = pduFactory.createPdu(bufferShort);
+
+            // ToDO figure out how to do this! makeEntityStatePDU
+            EntityStatePdu localEspdu = pduFactory.makeEntityStatePdu();
+            //Put all the data we need into the localEspdu
+            ByteBuffer espduByteBuffer = ByteBuffer.wrap(bufferShort);
+            try {
+                localEspdu.unmarshal(espduByteBuffer);
+            } catch (Exception ex) {
+                Logger.getLogger(X3dCreateLineSet.class.getName()).log(Level.SEVERE, null, ex);
+            }
+
+            double localTimeStamp;
+            double localX;
+            double localY;
+            double localZ;
+
+            //TimeStamps for a lineSet is not needed but copied from X3DInterpolators to use them as key for the hashmap
+            // and the standard compression class can be used
+            //Store the first timestamp to subtract it from all others
+            //Same with X,Y,Z to create a local coordiante system
+            if (firstTimeStamp) {
+
+                firstLocalTimeStamp = localPdu.getTimestamp();
+                firstLocalX = localEspdu.getEntityLocation().getX();
+                firstLocalY = localEspdu.getEntityLocation().getZ();
+                firstLocalZ = -1 * localEspdu.getEntityLocation().getY();
+
+                firstTimeStamp = false;
+            }
+
+            localTimeStamp = localPdu.getTimestamp();
+            localX = localEspdu.getEntityLocation().getX();
+            localY = localEspdu.getEntityLocation().getZ();
+            localZ = -1 * localEspdu.getEntityLocation().getY();
+
+            //Debug for printing X,Y,Z
+            //System.out.println(localX + " " + localY + " " + localZ);
+            localTimeStamp = localTimeStamp - firstLocalTimeStamp;
+            localX = localX - firstLocalX;
+            localY = localY - firstLocalY;
+            localZ = localZ - firstLocalZ;
+
+            //Divide TimeStamp by 1,300,000 to get something close to a second per Unit.
+            //According to the DIS standard one tick is 3600/(2^31) seconds ~ 1.6764 µs
+            //1,300,000 was derived from a stream that is 61 seconds long. The number was adjusted to get a timesensor with 61 seconds
+            //ToDo find the real conversion between TimeStampDelta and seconds
+            localTimeStamp = localTimeStamp / 1300000;
+
+            //Only add to stream if it is an ESPDU
+            //ToDo: Add support for multiple Entities
+            if ((localPdu.getPduType() != null) && (localPdu.getPduType() == DisPduType.ENTITY_STATE))
+                testMap.put(localTimeStamp, new X3dCoordinates(localX, localY, localZ, 0.0, 0.0, 0.0));
+        }
+    }
+
+    public void makeX3dLineSet() {
+
+        //Compression of the testMap.
+        //Remove all collinear points.
+        X3dSlidingWindowCompression regression = new X3dSlidingWindowCompression(testMap);
+
+        //To turn of the compression just comment the next line out and the very next in.
+        Map<Double, X3dCoordinates> returnMap = regression.doSlidingWindow();
+        //returnMap.putAll(testMap);
+
+        //Writing all values from the KeyMap to a proper Position Interpolator String
+        System.out.println("Writing X3D LineSet");
+        Set<Double> keys = returnMap.keySet();
+        String lineSetPoints = "";
+        String lineSet = "<LineSet vertexCount='" + returnMap.size() + "'> \n <Coordinate point='";
+
+        //Find highest time to do the normalization
+        double lastTimeStamp = 0;
+
+        for (Double k : keys) {
+
+            if (k > lastTimeStamp)
+                lastTimeStamp = k;
+        }
+
+        //Normalize all times in the set
+        Map<Double, String> keyKeyValueSetPositionInterpolator = new LinkedHashMap<>();
+
+        for (Double k : keys) {
+
+            String localCoordinateString;
+
+            double tempX = returnMap.get(k).getX();
+            double tempY = returnMap.get(k).getY();
+            double tempZ = returnMap.get(k).getZ();
+
+            localCoordinateString = " " + coordinateNumberFormat.format(tempX) + " " + coordinateNumberFormat.format(tempY) + " " + coordinateNumberFormat.format(tempZ);
+
+            keyKeyValueSetPositionInterpolator.put(k / lastTimeStamp, localCoordinateString);
+
+        }
+
+        keys = keyKeyValueSetPositionInterpolator.keySet();
+
+     
+
+        //Setting up PositionInterpolator and OrientationInterpolator
+        for (Double k : keys)
+            lineSetPoints += keyKeyValueSetPositionInterpolator.get(k) + " ";
+
+        lineSetPoints += "' ";
+
+        //PositionInterpolator
+
+        lineSet += lineSetPoints;
+        lineSet += "/>\n</LineSet> \n";
+
+        //Printing PositionInterpolator to the console
+        System.out.println(lineSet);
+    }
+
+}