From 8f585baae2c0797d8106a3535362dcc5a418e21a Mon Sep 17 00:00:00 2001 From: "John M. Penn" Date: Wed, 19 Oct 2016 18:20:32 -0500 Subject: [PATCH] Worked out a design for the Cannonball Variable server client that I'm happy with. Ref#320 --- .../models/graphics/src/CannonDisplay.java | 585 ++++++++++-------- 1 file changed, 328 insertions(+), 257 deletions(-) diff --git a/trick_sims/Cannon/models/graphics/src/CannonDisplay.java b/trick_sims/Cannon/models/graphics/src/CannonDisplay.java index 67e3c710..1652919d 100644 --- a/trick_sims/Cannon/models/graphics/src/CannonDisplay.java +++ b/trick_sims/Cannon/models/graphics/src/CannonDisplay.java @@ -30,7 +30,7 @@ import javax.swing.event.ChangeListener; * @author penn */ -class ArenaMap extends JPanel { +class RangeView extends JPanel { private int scale; private Color skyColor; @@ -40,38 +40,42 @@ class ArenaMap extends JPanel { private Color carriageColor; private Color wheelColor; private Color[] explosionColors; - int explosionColors_n; + private int explosionColors_n; // Origin of world coordinates in jpanel coordinates. - int Orig_w_j_x; - int Orig_w_j_y; + private int worldOriginX; + private int worldOriginY; - int barrelAngle; - int muzzleVelocity; - double[] cannonBallPos; + private int barrelAngle; + private int muzzleSpeed; + private double[] cannonBallPos; + private double[] cannonBallVel; - double explosionTime; - double[] barrelPivotPos; - double[] explosionPos; - double[] wheelCenterPos; - double wheelHubRadius; - double cannonBallRadius; + private double explosionSize; + private double[] barrelPivotPos; + private double[] explosionPos; + private double[] wheelCenterPos; + private double wheelHubRadius; + private double cannonBallRadius; - double[] barrel_x, barrel_y; - int barrel_n; + private double[] barrel_x, barrel_y; + private int barrel_n; - double[] carriage_x, carriage_y; - int carriage_n; + private double[] carriage_x, carriage_y; + private int carriage_n; - double[] wheel_section_x, wheel_section_y; - int wheel_section_n; + private double[] wheel_section_x, wheel_section_y; + private int wheel_section_n; - double[] explosion_poly_x, explosion_poly_y; - int explosion_poly_n; + private double[] explosion_poly_x, explosion_poly_y; + private int explosion_poly_n; - int[] poly_x, poly_y; + private int[] workPolyX, workPolyY; - public ArenaMap( int mapScale) { + /** + * Class constructor. + */ + public RangeView( int mapScale) { setScale(mapScale); @@ -90,85 +94,70 @@ class ArenaMap extends JPanel { explosionColors_n = 4; barrelAngle = 0; - muzzleVelocity = 0; + muzzleSpeed = 0; + explosionSize = 0.0; - explosionTime = 0.0; cannonBallPos = new double[] - // { -4.00, 37.00}; {-0.1020, 0.9400}; + + cannonBallVel = new double[] + {0.0, 0.0}; + barrelPivotPos = new double[] - // { -4.00, 37.00}; {-0.1020, 0.9400}; explosionPos = new double[] { 5.0800, 0.0000}; wheelCenterPos = new double[] - // { 0.00, 25.00}; { 0.0000,0.6350,}; + wheelHubRadius = 0.1524; cannonBallRadius = 0.1524; + // Cannon barrel polygon barrel_x = new double[] - //{ 50.00, 3.00,-19.00,-23.00,-25.00,-25.00,-25.00,-23.00,-19.00, 3.00, - // 50.00}; { 1.2700, 0.0762,-0.4826,-0.5842,-0.6350,-0.6350,-0.6350,-0.5842,-0.4826, 0.0762, 1.2700}; - barrel_y = new double[] - // { 4.00, 6.00, 6.00, 5.00, 2.00, 0.00, -2.00, -5.00, -6.00, -6.00, - // -4.00}; { 0.1016, 0.1524, 0.1524, 0.1270, 0.0508, 0.0000,-0.0508,-0.1270,-0.1524,-0.1524, -0.1016}; barrel_n = 11; + // Carriage polygon carriage_x = new double[] - // {-49.00, 1.00, 0.00, 6.00, 8.00, 17.00, 14.00, 1.00, 2.00, 2.00, - // 0.00, -1.00, -2.00,-52.00,-55.00,-57.00,-58.00,-58.00,-57.00,-56.00}; {-1.2446, 0.0254, 0.0000, 0.1524, 0.2032, 0.4318, 0.3556, 0.0254, 0.0508, 0.0508, 0.0000,-0.0254,-0.0508,-1.3208,-1.3970,-1.4478,-1.4732,-1.4732,-1.4478,-1.4224}; carriage_y = new double[] - // {-37.00,-13.00,-10.00, -7.00,-10.00, -6.00, 2.00, 2.00, 0.00, -1.00, - // -2.00, -1.00, 0.00,-30.00,-30.00,-31.00,-32.00,-35.00,-36.00,-37.00}; {-0.9398,-0.3302,-0.2540,-0.1778,-0.2540,-0.1524, 0.0508, 0.0508, 0.0000,-0.0254, -0.0508,-0.0254, 0.0000,-0.7620,-0.7620,-0.7874,-0.8128,-0.8890,-0.9144,-0.9398}; carriage_n = 20; + // Wheel Section polygon wheel_section_x = new double[] - // { 1.00, 1.00, 5.69, 6.47, 3.26, 0.00, -3.26, -6.47, -5.69, -1.00, - // -1.00}; { 0.0254, 0.0254, 0.1445, 0.1643, 0.0828, 0.0000,-0.0828,-0.1643,-0.1445,-0.0254, -0.0254}; wheel_section_y = new double[] - // { 3.00, 22.00, 21.25, 24.15, 24.78, 25.00, 24.78, 24.15, 21.25, 22.00, - // 3.00}; { 0.0762, 0.5588, 0.5398, 0.6134, 0.6294, 0.6350, 0.6294, 0.6134, 0.5398, 0.5588, 0.0762}; wheel_section_n = 11; + // Explosion polygon explosion_poly_x = new double[] - // { 0.70, 0.97, 0.63, 0.78, 0.44, 0.43, 0.16, 0.00, -0.16, -0.43, - // -0.44, -0.78, -0.63, -0.97, -0.70, -0.97, -0.63, -0.78, -0.44, -0.43, - // -0.16, 0.00, 0.16, 0.43, 0.44, 0.78, 0.63, 0.97, 0.70}; { 0.0178, 0.0246, 0.0160, 0.0198, 0.0112, 0.0109, 0.0041, 0.0000,-0.0041,-0.0109, -0.0112,-0.0198,-0.0160,-0.0246,-0.0178,-0.0246,-0.0160,-0.0198,-0.0112,-0.0109, -0.0041, 0.0000, 0.0041, 0.0109, 0.0112, 0.0198, 0.0160, 0.0246, 0.0178}; explosion_poly_y = new double[] - // { 0.00, 0.22, 0.30, 0.62, 0.55, 0.90, 0.68, 1.00, 0.68, 0.90, - // 0.55, 0.62, 0.30, 0.22, 0.00, -0.22, -0.30, -0.62, -0.55, -0.90, - // -0.68, -1.00, -0.68, -0.90, -0.55, -0.62, -0.30, -0.22, 0.00}; { 0.0000, 0.0056, 0.0076, 0.0157, 0.0140, 0.0229, 0.0173, 0.0254, 0.0173, 0.0229, 0.0140, 0.0157, 0.0076, 0.0056, 0.0000,-0.0056,-0.0076,-0.0157,-0.0140,-0.0229, -0.0173,-0.0254,-0.0173,-0.0229,-0.0140,-0.0157,-0.0076,-0.0056, 0.0000}; explosion_poly_n = 29; - poly_x = new int[30]; - poly_y = new int[30]; - } - - public void initCannonballPos() { - cannonBallPos[0] = -0.1020; - cannonBallPos[1] = 0.9400; + workPolyX = new int[30]; + workPolyY = new int[30]; } + /** + @param value angle in degrees + */ public void setBarrelAngle(int value) { barrelAngle = value; repaint(); @@ -178,19 +167,32 @@ class ArenaMap extends JPanel { return barrelAngle; } - public void setMuzzleVelocity(int value) { - muzzleVelocity = value; + public void setMuzzleSpeed(int value) { + muzzleSpeed = value; repaint(); } public int getMuzzleVelocity() { - return muzzleVelocity; + return muzzleSpeed; } public void setCannonBallPos(double x, double y) { cannonBallPos[0] = x; cannonBallPos[1] = y; - repaint(); + } + + public void setCannonBallVel(double vx, double vy) { + cannonBallVel[0] = vx; + cannonBallVel[1] = vy; + } + + public void setExplosionSize(double size) { + explosionSize = size; + } + + public void setExplosionPos(double x, double y) { + explosionPos[0] = x; + explosionPos[1] = y; } public void setScale (int mapScale) { @@ -228,105 +230,121 @@ class ArenaMap extends JPanel { int width = getWidth(); int height = getHeight(); - // NOTE: is the orig of the world coordinate system expressed in jpanel coords. - // This origin tracks the position of the cannonball. - Orig_w_j_x = (width/2) - (int)(scale * cannonBallPos[0]); - Orig_w_j_y = getHeight()-20; + worldOriginX = (width/2) - (int)(scale * cannonBallPos[0]); + worldOriginY = (height/2) + (int)(scale * cannonBallPos[1]); // Draw Sky g2d.setPaint(skyColor); - g2d.fillRect(0, 0, width, Orig_w_j_y); + g2d.fillRect(0, 0, width, worldOriginY); - // |jpanel_x| = |origin_x| + scale * |1 0| * | cosa -sina| * |world_x| - // |jpanel_y| |origin_y| |0 -1| | sina cosa| |world_y| + // Draw Clouds + g2d.setPaint(Color.WHITE); + g2d.fillOval((int)(worldOriginX + scale * 500), (int)(worldOriginY - scale * 20), (int)(scale*20), (int)(scale*5)); + g2d.fillOval((int)(worldOriginX + scale * 510), (int)(worldOriginY - scale * 22), (int)(scale*15), (int)(scale*5)); + g2d.fillOval((int)(worldOriginX + scale * 200), (int)(worldOriginY - scale * 20), (int)(scale*20), (int)(scale*5)); + g2d.fillOval((int)(worldOriginX + scale * 200), (int)(worldOriginY - scale * 22), (int)(scale*15), (int)(scale*5)); + g2d.fillOval((int)(worldOriginX + scale * 0), (int)(worldOriginY - scale * 15), (int)(scale*10), (int)(scale*2)); + // |jpanel_x| = |origin_x| + |scale 0 | * |cos(angle) -sin(angle)| * |world_x| + // |jpanel_y| |origin_y| | 0 -scale| |sin(angle) cos(angle)| |world_y| // Draw cannon ball - g2d.setPaint(cannonBallColor); - int bx = (int)(Orig_w_j_x + scale * cannonBallPos[0]); - int by = (int)(Orig_w_j_y - scale * cannonBallPos[1]); - drawCenteredCircle(g2d, bx, by, (int)(scale * cannonBallRadius)); + g2d.setPaint(cannonBallColor); + int bx = (int)(worldOriginX + scale * cannonBallPos[0]); + int by = (int)(worldOriginY - scale * cannonBallPos[1]); + drawCenteredCircle(g2d, bx, by, (int)(scale * cannonBallRadius)); + + double velMag = Math.sqrt(cannonBallVel[0]*cannonBallVel[0] + cannonBallPos[1]*cannonBallPos[1]); + if (velMag > 0.1) { + g2d.setPaint(Color.RED); + int vx = (int)(worldOriginX + scale * (cannonBallPos[0] - cannonBallVel[0]/velMag)); + int vy = (int)(worldOriginY - scale * (cannonBallPos[1] - cannonBallVel[1]/velMag)); + g2d.drawLine( bx, by, vx, vy); + } // Draw cannon barrel double angle = Math.toRadians(barrelAngle); - for (ii = 0; ii 0.0) { + // Draw explosion. + if ( explosionSize > 0.0 ) { for (jj = 0; jj < explosionColors_n ; jj ++) { for (ii = 0; ii < explosion_poly_n ; ii ++) { - double ex = explosionTime * explosionTime * 5.0 * (explosionColors_n - jj) * explosion_poly_x[ii]; - double ey = explosionTime * explosionTime * 5.0 * (explosionColors_n - jj) * explosion_poly_y[ii]; - poly_x[ii] = (int)(Orig_w_j_x + scale * (ex + explosionPos[0] )); - poly_y[ii] = (int)(Orig_w_j_y - scale * (ey + explosionPos[1] )); + double ex = explosionSize * (explosionColors_n - jj) * explosion_poly_x[ii]; + double ey = explosionSize * (explosionColors_n - jj) * explosion_poly_y[ii]; + workPolyX[ii] = (int)(worldOriginX + scale * (ex + explosionPos[0] )); + workPolyY[ii] = (int)(worldOriginY - scale * (ey + explosionPos[1] )); } g2d.setPaint(explosionColors[jj]); - g2d.fillPolygon(poly_x, poly_y, explosion_poly_n); + g2d.fillPolygon(workPolyX, workPolyY, explosion_poly_n); } } - // Draw Ground + // Draw ground. g2d.setPaint(groundColor); - g2d.fillRect(0, Orig_w_j_y, width, height); + g2d.fillRect(0, worldOriginY, width, height); - - // Draw Range Markers + // Draw range markers. int tickRange = 50; - if (scale >= 8) tickRange =20; - if (scale >= 16) tickRange =10; - if (scale >= 32) tickRange = 5; - if (scale >= 64) tickRange = 1; + if (scale >= 8) tickRange = 20; + if (scale >= 16) tickRange = 10; + if (scale >= 32) tickRange = 5; + if (scale >= 64) tickRange = 1; - double lower = -Orig_w_j_x / scale; - double upper = (width - Orig_w_j_x) / scale; - - int LL = ((int)(lower/tickRange) + 1) * tickRange; - int UU = ((int)(upper/tickRange) + 1) * tickRange; + int lower = ((int)(( - worldOriginX)/(scale * tickRange)) + 1) * tickRange; + int upper = ((int)((width - worldOriginX)/(scale * tickRange)) + 1) * tickRange; g2d.setPaint(Color.BLACK); - for (int kk = LL ; kk < UU ; kk += tickRange) { - int mx = (int)(Orig_w_j_x + scale * kk); - g2d.drawLine( mx, Orig_w_j_y, mx, Orig_w_j_y+20); - g2d.drawString ( String.format("%d",kk), mx, Orig_w_j_y+15); - + for (ii = lower ; ii < upper ; ii += tickRange) { + int mx = (int)(worldOriginX + scale * ii); + g2d.drawLine( mx, worldOriginY, mx, worldOriginY + 20); + g2d.drawString ( String.format("%d",ii), mx, worldOriginY + 15); } - g2d.drawString ( String.format("SCALE: %d",scale), 20,20); - g2d.drawString ( String.format("Cannon barrel angle: [%d]",barrelAngle), 20,40); - g2d.drawString ( String.format("Cannon muzzle velocity: [%d]",muzzleVelocity), 20,60); - g2d.drawString ( String.format("Cannonball Pos: [%.2f, %.2f]",cannonBallPos[0],cannonBallPos[1]), 20,80); + g2d.drawString ( String.format("SCALE: %d pixels/meter",scale), 20,20); + g2d.drawString ( String.format("Barrel angle: [%d]", barrelAngle), 20,40); + g2d.drawString ( String.format("Muzzle speed: [%d]", muzzleSpeed), 20,60); + g2d.drawString ( String.format("Cannonball Pos: [%.2f, %.2f]", cannonBallPos[0], cannonBallPos[1]), 20,80); + g2d.drawString ( String.format("Cannonball Vel: [%.2f, %.2f]", cannonBallVel[0], cannonBallVel[1]), 20,100); + } @Override @@ -340,7 +358,7 @@ class ElevationPanel extends JPanel implements ChangeListener { static final int ANGLE_MIN = 0; static final int ANGLE_MAX = 90; - static final int ANGLE_INIT = 45; + static final int ANGLE_INIT = 30; private CannonDisplay cannonDisplay; private JSlider angleSlider ; @@ -365,6 +383,7 @@ class ElevationPanel extends JPanel implements ChangeListener { } + @Override public void stateChanged(ChangeEvent e) { JSlider source = (JSlider)e.getSource(); if (!source.getValueIsAdjusting()) { @@ -407,10 +426,11 @@ class MuzzleVelPanel extends JPanel implements ChangeListener { add(velSlider); } + @Override public void stateChanged(ChangeEvent e) { JSlider source = (JSlider)e.getSource(); if (!source.getValueIsAdjusting()) { - cannonDisplay.setMuzzleVelocity( source.getValue() ); + cannonDisplay.setMuzzleSpeed( source.getValue() ); } } @@ -442,7 +462,7 @@ class ButtonPanel extends JPanel implements ActionListener { fireButton.setToolTipText("Fire Cannon"); add(fireButton); - armButton = new JButton("ARM"); + armButton = new JButton("RELOAD"); armButton.addActionListener(this); armButton.setActionCommand("arm"); armButton.setToolTipText("Arm Cannon"); @@ -484,13 +504,13 @@ class ButtonPanel extends JPanel implements ActionListener { } } - public void AcknowledgeArmed() { + public void resetArmCommand() { armCommand = false; armAcknowledged = true; fireButton.setForeground(Color.red); } - public void AcknowledgeFired() { + public void resetFireCommand() { fireCommand = false; fireButton.setForeground(Color.gray); } @@ -504,10 +524,15 @@ class ButtonPanel extends JPanel implements ActionListener { } // class ButtonPanel +class TrickSimMode { + public static final int INIT = 0; + public static final int FREEZE = 1; + public static final int RUN = 5; +} public class CannonDisplay extends JFrame { - private ArenaMap arenaMap; + private RangeView rangeView; private ElevationPanel elevPanel; private MuzzleVelPanel velPanel; private BufferedReader in; @@ -515,20 +540,19 @@ public class CannonDisplay extends JFrame { private JPanel panelGroup0; private JPanel panelGroup1; private ButtonPanel buttonPanel; - private JButton b1, b2, b3, b4, b5; - public CannonDisplay(ArenaMap arena) { + public CannonDisplay(RangeView arena) { setTitle("Cannon Range"); elevPanel = new ElevationPanel(this); velPanel = new MuzzleVelPanel(this); - arenaMap = arena; + rangeView = arena; panelGroup1 = new JPanel(); panelGroup1.setLayout(new BoxLayout(panelGroup1, BoxLayout.X_AXIS)); panelGroup1.add(elevPanel); panelGroup1.add(velPanel); - panelGroup1.add(arenaMap); + panelGroup1.add(rangeView); buttonPanel = new ButtonPanel(this); @@ -540,51 +564,62 @@ public class CannonDisplay extends JFrame { setScale(32); setBarrelAngle(30); - setMuzzleVelocity(500); + setMuzzleSpeed(50); setCannonBallPos (-0.1020, 0.9400); - setSize(800, 500); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public int getBarrelAngle() { - return arenaMap.getBarrelAngle(); + return rangeView.getBarrelAngle(); } public void setBarrelAngle(int value) { - arenaMap.setBarrelAngle(value); + rangeView.setBarrelAngle(value); elevPanel.setValue(value); } public int getMuzzleVelocity() { - return arenaMap.getMuzzleVelocity(); + return rangeView.getMuzzleVelocity(); } - public void setMuzzleVelocity(int value) { - arenaMap.setMuzzleVelocity(value); + public void setMuzzleSpeed(int value) { + rangeView.setMuzzleSpeed(value); velPanel.setValue(value); } public void setCannonBallPos(double x, double y) { - arenaMap.setCannonBallPos(x,y); + rangeView.setCannonBallPos(x,y); + } + + public void setCannonBallVel(double vx, double vy) { + rangeView.setCannonBallVel(vx,vy); + } + + public void setExplosionSize(double size) { + rangeView.setExplosionSize(size); + } + + public void setExplosionPos(double x, double y) { + rangeView.setExplosionPos(x,y); } public void setScale(int value) { - arenaMap.setScale(value); + rangeView.setScale(value); } public int getScale() { - return arenaMap.getScale(); + return rangeView.getScale(); } - public void AcknowledgeArmed() { - buttonPanel.AcknowledgeArmed(); + public void resetArmCommand() { + buttonPanel.resetArmCommand(); } - public void AcknowledgeFired() { - buttonPanel.AcknowledgeFired(); + public void resetFireCommand() { + buttonPanel.resetFireCommand(); } public boolean getArmCommand() { @@ -601,8 +636,8 @@ public class CannonDisplay extends JFrame { out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())); } - public void drawArenaMap() { - arenaMap.repaint(); + public void drawRangeView() { + rangeView.repaint(); } private static void printHelpText() { @@ -613,11 +648,16 @@ public class CannonDisplay extends JFrame { ); } + public enum ModelState { INACTIVE, READY, ACTIVE } + public static void main(String[] args) throws IOException, InterruptedException { String host = "localHost"; int port = 0; + // ========================================================== + // Handle program arguments. + // ========================================================== int ii = 0; while (ii < args.length) { switch (args[ii]) { @@ -633,144 +673,175 @@ public class CannonDisplay extends JFrame { ++ii; } -// if (port == 0) { -// System.out.println("No variable server port specified."); -// printHelpText(); -// System.exit(0); -// } + boolean go = true; + double dt = 0.100; // Time between updates (seconds). + double posx = 0.0; + double posy = 0.0; + double velx = 0.0; + double vely = 0.0; + double angle; + double speed; + boolean impact = false; + boolean prevImpact = false; + boolean armCommand; + boolean fireCommand; + int simMode = 0; + + int exticks = 0; + double exTime = 0.0; + ModelState explosionModelState = ModelState.INACTIVE; int mapScale = 32 ; // pixels per meter. - ArenaMap arenaMap = new ArenaMap( mapScale); - CannonDisplay evd = new CannonDisplay( arenaMap); + + RangeView rangeView = new RangeView( mapScale); + CannonDisplay evd = new CannonDisplay( rangeView); evd.setVisible(true); - -// System.out.println("Connecting to: " + host + ":" + port); -// evd.connectToServer(host, port); -// -// evd.out.writeBytes("trick.var_set_client_tag(\"CannonDisplay\") \n"); -// evd.out.flush(); -// -// evd.out.writeBytes("trick.var_add(\"dyn.cannon.pos[0]\") \n" + -// "trick.var_add(\"dyn.cannon.pos[1]\") \n" + -// "trick.var_add(\"dyn.cannon.pos[1]\") \n"); -// evd.out.flush(); -// -// evd.out.writeBytes("trick.var_ascii() \n" + -// "trick.var_cycle(0.1) \n" + -// "trick.var_send() \n" ); -// evd.out.flush(); + evd.drawRangeView(); - boolean fireCommand = false; - boolean armCommand = false; - boolean armed = false; - boolean fired = false; - boolean impact = false; - double impactTime = 0.0; - int ticks = 0; - int cTimeRate = 0; - double cTime = 0.0; - int cticks = 0; - int exTimeRate = 0; // 0 or 1 - double exTime = 0.0; - int exticks = 0; - double posx = 0.0; - double posy = 0.0; - double posx0 = 0.0; - double posy0 = 0.0; - double exposx = 0.0; - double exposy = 0.0; - double speed = 0.0; - double angle = 0.0; - double elev = 0.0; - double simdt = 0.100; + if (port == 0) { + System.out.println("No variable server port specified."); + printHelpText(); + System.exit(0); + } - evd.drawArenaMap(); + // Connect to the Trick simulation's variable server + System.out.println("Connecting to: " + host + ":" + port); + evd.connectToServer(host, port); + + evd.out.writeBytes("trick.var_set_client_tag(\"CannonDisplay\") \n"); + evd.out.flush(); + + // Have the Variable Server send us the simulation mode ONCE. + evd.out.writeBytes( "trick.var_add(\"trick_sys.sched.mode\")\n" + + "trick.var_send() \n" + + "trick.var_clear() \n"); + evd.out.flush(); + + // Read the response and extract the simulation mode. + try { + String line; + String field[]; + line = evd.in.readLine(); + field = line.split("\t"); + simMode = Integer.parseInt( field[1]); + } catch (IOException | NullPointerException e ) { + go = false; + } + + // If we're in FREEZE, make ready to fire. + if (simMode == TrickSimMode.FREEZE) { + evd.resetArmCommand(); + } + + // Configure the Variable Server to cyclically send us the following varibales. + // Tell the variable server: + // 1) We want the values of the following variables: + evd.out.writeBytes( "trick.var_add(\"dyn.cannon.impact\")\n" + + "trick.var_add(\"dyn.cannon.pos[0]\")\n" + + "trick.var_add(\"dyn.cannon.pos[1]\")\n" + + "trick.var_add(\"dyn.cannon.vel[0]\")\n" + + "trick.var_add(\"dyn.cannon.vel[1]\")\n" + + "trick.var_add(\"trick_sys.sched.mode\")\n"); + // 2) We want the responses in ASCII: + evd.out.writeBytes("trick.var_ascii() \n"); + // 3) We want values to be updated at the specified rate: + evd.out.writeBytes( String.format("trick.var_cycle(%.3f)\n", dt)); + // 4) Start sending values as specified. + evd.out.writeBytes("trick.var_send() \n" ); + evd.out.flush(); - Boolean go = true; while (go) { - Thread.sleep((int)(1000 * simdt)); - ticks ++; + + // Recieve and parse periodic data response from the variable server. + try { + String line; + String field[]; + line = evd.in.readLine(); + field = line.split("\t"); + impact = ( Integer.parseInt( field[1]) != 0); + posx = Double.parseDouble( field[2]); + posy = Double.parseDouble( field[3]); + velx = Double.parseDouble( field[4]); + vely = Double.parseDouble( field[5]); + simMode = Integer.parseInt( field[6]); + } catch (IOException | NullPointerException e ) { + go = false; + } - // === DATA OUT TO THE SIM === + if (simMode == TrickSimMode.RUN) { + evd.resetFireCommand(); + } + + // Update the display data. + evd.setCannonBallPos(posx, posy); + evd.setCannonBallVel(velx, vely); + + // Get inputs from the GUI. angle = evd.getBarrelAngle(); speed = evd.getMuzzleVelocity(); - armCommand = evd.getArmCommand(); fireCommand = evd.getFireCommand(); - // ============================= - if (cTimeRate == 0) { + if (simMode == TrickSimMode.FREEZE) { if (armCommand) { - posx0 = posx = -0.1020; - posy0 = posy = 0.9400; - armed = true; - fired = false; + evd.out.writeBytes( String.format("dyn.cannon.pos[0] = %.2f ;\n", -0.1020 )); + evd.out.writeBytes( String.format("dyn.cannon.pos[1] = %.2f ;\n", 0.9400 )); + evd.out.writeBytes( String.format("dyn.cannon.vel[0] = %.2f ;\n", 0.0000 )); + evd.out.writeBytes( String.format("dyn.cannon.vel[1] = %.2f ;\n", 0.0000 )); + evd.out.flush(); + evd.resetArmCommand(); } - if (fireCommand && armed ) { - elev = angle * (3.14159/180.0); - cticks = 0; - cTimeRate = 1; - armed = false; - fired = true; - } - } else { - cticks ++; - cTime = cticks * cTimeRate * simdt; - posx = posx0 + cTime * speed * Math.cos(elev) ; - posy = posy0 + cTime * (speed * Math.sin(elev) + 0.5 * -9.81 * cTime); - - if (posy < 0.0) { - impact = true; - impactTime = ((2 * speed * Math.sin(elev)) / 9.81); - posx = impactTime * speed * Math.cos(elev); - posy = 0; - cTimeRate = 0; //Stop Cannonball + if (fireCommand) { + evd.out.writeBytes( String.format("dyn.cannon.init_angle = %.2f ;\n", Math.toRadians(angle))); + evd.out.writeBytes( String.format("dyn.cannon.init_speed = %.2f;\n", speed )); + evd.out.writeBytes( String.format("dyn.cannon.pos0[0] = %.2f ;\n", -0.1020 )); + evd.out.writeBytes( String.format("dyn.cannon.pos0[1] = %.2f ;\n", 0.9400 )); + evd.out.writeBytes( String.format("dyn.cannon.time = %.2f ;\n", 0.0 )); + evd.out.writeBytes( String.format("trick.cannon_init( dyn.cannon );\n" )); + evd.out.writeBytes( String.format("trick.exec_run();\n" )); + evd.resetFireCommand(); + evd.out.flush(); } } - if (exTimeRate == 0) { - if (impact) { - impact = false; - exposx = posx; - exposy = posy; - - // Start Explosion - exticks = 0; - exTimeRate = 1; - - } - } else { - exticks ++; - exTime = exticks * exTimeRate * simdt; - - if (exTime > 4.0) { - exTimeRate = 0; - exTime = 0.0; + if (simMode == TrickSimMode.RUN) { + if (impact && !prevImpact) { + evd.out.writeBytes( String.format("trick.exec_freeze();\n" )); + evd.out.flush(); } } - System.out.print("cTime = " + String.format("%.5f",cTime) ); - System.out.print(" exTime = " + String.format("%.5f",exTime) ); - System.out.println(" ticks = " + String.format("%d",ticks) ); - - // ==== DATA IN FROM THE SIM ==== - evd.setCannonBallPos(posx, posy); - if (armed) { - evd.AcknowledgeArmed(); + // Explosion Model + exticks ++; + exTime = exticks * dt; + switch(explosionModelState) { + case INACTIVE: + if (impact && !prevImpact) { // Trigger on leading edge. + exticks = 0; + evd.setExplosionPos(posx, posy); + explosionModelState = ModelState.ACTIVE; + } + break; + case ACTIVE: + if (exTime > 4.0) { + evd.setExplosionSize(0.0); + explosionModelState = ModelState.INACTIVE; + } else if (exTime > 0.0) { + evd.setExplosionSize(exTime * exTime * 5.0); + } else { + evd.setExplosionSize(0.0); + } + break; + default: + break; } - if (fired) { - evd.AcknowledgeFired(); - } - arenaMap.explosionTime = exTime; - arenaMap.explosionPos[0] = exposx; - arenaMap.explosionPos[1] = exposy; - - // ============================= + prevImpact = impact; + // Update the scene. + evd.drawRangeView(); - evd.drawArenaMap(); - } - } -} + } // while + } // main +} // class