diff --git a/trick_sims/SIM_life/Notes.txt b/trick_sims/SIM_life/Notes.txt new file mode 100644 index 00000000..920e9628 --- /dev/null +++ b/trick_sims/SIM_life/Notes.txt @@ -0,0 +1,11 @@ +Entity + :Objects + -Parts + :Organism + -BodyParts + +Shapes + :Circle, Triangle, Rectangle + :Parts + :BodyParts + :Various Specific BodyParts diff --git a/trick_sims/SIM_life/models/graphics/Makefile b/trick_sims/SIM_life/models/graphics/Makefile new file mode 100644 index 00000000..d3e0cbc0 --- /dev/null +++ b/trick_sims/SIM_life/models/graphics/Makefile @@ -0,0 +1,6 @@ + +all: + mvn package + +clean: + rm -rf build diff --git a/trick_sims/SIM_life/models/graphics/pom.xml b/trick_sims/SIM_life/models/graphics/pom.xml new file mode 100644 index 00000000..2651af39 --- /dev/null +++ b/trick_sims/SIM_life/models/graphics/pom.xml @@ -0,0 +1,121 @@ + + + + 4.0.0 + + trick-java + trick-java + 23.0.0-beta + + trick-java + + https://github.com/nasa/trick + + + UTF-8 + 1.8 + 1.8 + + + + + junit + junit + 4.13.1 + test + + + + + + WaterClockDisplay + + build + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.1.1 + + ${java.home}/bin/javadoc + ../../share/doc/trick/java + + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + + maven-resources-plugin + 3.0.2 + + + + maven-compiler-plugin + 3.8.0 + + + -g + -Xlint:unchecked + -Xlint:deprecation + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + + true + lib/ + WaterClockDisplay + + + + + + + maven-surefire-plugin + 2.22.1 + + + + maven-install-plugin + 2.5.2 + + + + maven-deploy-plugin + 2.8.2 + + + + + maven-site-plugin + 3.7.1 + + + + + + + + diff --git a/trick_sims/SIM_life/models/graphics/src/main/java/trick/waterClockDisplay/WaterClockDisplay.java b/trick_sims/SIM_life/models/graphics/src/main/java/trick/waterClockDisplay/WaterClockDisplay.java new file mode 100644 index 00000000..c3cbcace --- /dev/null +++ b/trick_sims/SIM_life/models/graphics/src/main/java/trick/waterClockDisplay/WaterClockDisplay.java @@ -0,0 +1,779 @@ +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Graphics; +import java.awt.RenderingHints; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.Socket; +import java.util.*; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.sound.sampled.*; +import java.net.URL; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Rectangle2D; +import java.awt.Font; + +import javax.swing.text.NumberFormatter; +import java.text.NumberFormat; +import javax.swing.JFormattedTextField; +import java.awt.Dimension; + +import javax.swing.BorderFactory; +import javax.swing.border.EtchedBorder; +import java.awt.Component; + +class ScenePoly { + public Color color; + public int n; + public double[] x; + public double[] y; +} + +class RangeView extends JPanel { + + private int scale; + private Color bucket_color; + private Color spout_color; + private Color water_color; + private Color float_color; + private Color clock_color; + private Color clock_display_color; + private Color tick_color; + private Color gear_color; + + // Origin of world coordinates in jpanel coordinates. + private int worldOriginX; + private int worldOriginY; + + private double spout_rate; + private double overflow_rate; + private double intake_depth; + private double timer_depth; + private double intake_lvl; + private double timer_lvl; + private double intake_vol; + private double timer_vol; + private double spout_height; + private double overflow_height; + private double input_flow; + private int current_tick; + + private double clock_float_height; + + // Controls + private double input_flow_select; + public boolean new_input_flow; + + /** + * Class constructor. + */ + public RangeView( int mapScale) { + + setScale(mapScale); + + spout_rate = 0.0; + overflow_rate = 0.0; + intake_depth = 0.0; + timer_depth = 0.0; + intake_lvl = 0.0; + timer_lvl = 0.0; + intake_vol = 0.0; + timer_vol = 0.0; + spout_height = 0.0; + overflow_height = 0.0; + input_flow = 0.0; + input_flow_select = 0.0; + current_tick = 0; + + new_input_flow = false; + + bucket_color = new Color(150,75,0); + spout_color = new Color(128,128,128); + water_color = new Color(0,0,128); + float_color = new Color(0,0,0); + clock_color = new Color(204,204,0); + clock_display_color = new Color(192,192,192); + tick_color = new Color(0,0,0); + gear_color = new Color(128,128,128); + + workPolyX = new int[150]; + workPolyY = new int[150]; + + tooth = new ScenePoly(); + tooth.color = float_color; + + tooth.x = new double[] { 0, -0.15, -0.25 , -0.15 , 0 }; + tooth.y = new double[] { 0, 0 , 0.075 , 0.15 , 0.15 }; + + tooth.n = 5; + + clock_float_height = 8; + } + + private ScenePoly gear; + private ScenePoly tooth; + + private int[] workPolyX, workPolyY; + + public void fillSceneRect(Graphics2D g2d, Color color, double x, double y, double w, double h) { + g2d.setPaint(color); + g2d.fillRect( (int)(worldOriginX+scale*(x)), (int)(worldOriginY-scale*(y)), (int)(scale*w), (int)(scale*h)); + } + + public void fillScenePoly(Graphics2D g, ScenePoly p, double angle_r , double x, double y) { + for (int ii = 0; ii < p.n; ii++) { + workPolyX[ii] = (int)(worldOriginX + scale * + ( Math.cos(angle_r) * p.x[ii] - Math.sin(angle_r) * p.y[ii] + x)); + workPolyY[ii] = (int)(worldOriginY - scale * + ( Math.sin(angle_r) * p.x[ii] + Math.cos(angle_r) * p.y[ii] + y)); + } + g.setPaint(p.color); + g.fillPolygon(workPolyX, workPolyY, p.n); + } + + public void fillSceneOval(Graphics2D g2d, Color color, double x, double y, double w, double h) { + g2d.setPaint(color); + g2d.fillOval( (int)(worldOriginX+scale*(x-w/2)), (int)(worldOriginY-scale*(y+h/2)), (int)(scale*w), (int)(scale*h)); + } + + public void setSpoutRate(double x) { + spout_rate = x; + } + + public void setOverflowRate(double x) { + overflow_rate = x; + } + + public void setIntakeDepth(double x) { + intake_depth = x; + } + + public void setTimerDepth(double x) { + timer_depth = x; + } + + public void setIntakeWarerLevel(double x) { + intake_lvl = x; + } + + public void setTimerWarerLevel(double x) { + timer_lvl = x; + } + + public void setIntakeWaterVol(double x) { + intake_vol = x; + } + + public void setTimerWaterLevel(double x) { + timer_vol = x; + } + + public void setSpoutHeight(double x) { + spout_height = x; + } + + public void setOverflowHeight(double x) { + overflow_height = x; + } + + public void setInputFlow(double x) { + input_flow = x; + } + + public void setInputFlowSelect(double x) { + input_flow_select = x; + } + + public double getInputFlowSelect() { + return input_flow_select; + } + + public void setCurrentTick(int x) { + current_tick = x; + } + + public void setScale (int mapScale) { + if (mapScale < 2) { + scale = 2; + } else if (mapScale > 128) { + scale = 128; + } else { + scale = mapScale; + } + repaint(); + } + + private void doDrawing(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + + RenderingHints rh = new RenderingHints( + RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + rh.put(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_QUALITY); + + int width = getWidth(); + int height = getHeight(); + + worldOriginX = (width/2) - (int)(scale * 0); + worldOriginY = (height/2) + (int)(scale * 0); + + + // Draw intake Bucket + double bucket_length = 2.0; + double bucket_width = 0.15; + double intake_bucket_origin_x = 4; + double intake_bucket_origin_y = 1.7; + double intake_bucket_left_wall_x = intake_bucket_origin_x - bucket_length - bucket_width; + double intake_bucket_bottom_x = intake_bucket_origin_x - bucket_length - bucket_width; + double intake_bucket_bottom_y = intake_bucket_origin_y - bucket_length; + double spout_width = 0.175; + double spout_length = 1.0; + double spout_pipe_x = intake_bucket_left_wall_x - spout_length + bucket_width; + double spout_pipe_y = intake_bucket_origin_y - bucket_length + spout_width + ((spout_height / intake_depth) * bucket_length) - spout_width/2; + double overflow_pipe_x = intake_bucket_origin_x; + double overflow_pipe_y = intake_bucket_origin_y - bucket_length + spout_width + ((overflow_height / intake_depth) * bucket_length) - spout_width/2; + fillSceneRect( g2d, + bucket_color, + intake_bucket_origin_x, + intake_bucket_origin_y, + bucket_width, + bucket_length); + fillSceneRect( g2d, + bucket_color, + intake_bucket_bottom_x, + intake_bucket_bottom_y, + bucket_length + (2 * bucket_width), + bucket_width); + fillSceneRect( g2d, + bucket_color, + intake_bucket_left_wall_x, + intake_bucket_origin_y, + bucket_width, + bucket_length); + fillSceneRect( g2d, + spout_color, + overflow_pipe_x, + overflow_pipe_y, + spout_length, + spout_width); + fillSceneRect( g2d, + spout_color, + spout_pipe_x, + spout_pipe_y, + spout_length, + spout_width); + + //Draw timer bucket + double timer_bucket_origin_x = 1.3; + double timer_bucket_origin_y = -0.5; + double timer_bucket_left_wall_x = timer_bucket_origin_x - bucket_length - bucket_width; + double timer_bucket_bottom_x = timer_bucket_origin_x - bucket_length - bucket_width; + double timer_bucket_bottom_y = timer_bucket_origin_y - bucket_length; + fillSceneRect( g2d, + bucket_color, + timer_bucket_origin_x, + timer_bucket_origin_y, + bucket_width, + bucket_length); + fillSceneRect( g2d, + bucket_color, + timer_bucket_bottom_x, + timer_bucket_bottom_y, + bucket_length + (2 * bucket_width), + bucket_width); + fillSceneRect( g2d, + bucket_color, + timer_bucket_left_wall_x, + timer_bucket_origin_y, + bucket_width, + bucket_length); + + + //Draw water flow + double flow_width = 0.15; + double spout_flow_height = intake_bucket_origin_y - timer_bucket_origin_y + (bucket_length - (intake_bucket_origin_y - spout_pipe_y)) - spout_width/2; + double overflow_height = 20; + if (spout_rate != 0.0) { + fillSceneRect( g2d, + water_color, + intake_bucket_left_wall_x - spout_length + bucket_width - flow_width + 0.015, + spout_pipe_y - spout_width/2, + flow_width, + spout_flow_height); + } + + if (overflow_rate != 0.0) { + fillSceneRect( g2d, + water_color, + intake_bucket_origin_x + spout_length, + overflow_pipe_y - spout_width/2, + flow_width, + overflow_height); + } + + + //Draw water level + double intake_capacity = intake_lvl / intake_depth; + double intake_offset = ((1 - intake_capacity) * bucket_length) ; + double timer_capacity = timer_lvl / timer_depth; + double timer_offset = ((1 - timer_capacity) * bucket_length) ; + fillSceneRect( g2d, + water_color, + intake_bucket_origin_x - bucket_length - 0.01, + intake_bucket_origin_y - intake_offset, + bucket_length + 0.03, + intake_capacity * bucket_length); + //fill in pixel gaps due to rounding error + if(intake_lvl > 0.0) { + fillSceneRect( g2d, + water_color, + intake_bucket_origin_x - bucket_length - 0.01, + intake_bucket_origin_y - bucket_length + 0.05, + bucket_length + 0.03, + 0.05); + } + + + fillSceneRect( g2d, + water_color, + timer_bucket_origin_x - bucket_length - 0.01, + timer_bucket_origin_y - timer_offset, + bucket_length + 0.03, + timer_capacity * bucket_length); + //fill in pixel gaps due to rounding error + if(timer_lvl > 0.0) { + fillSceneRect( g2d, + water_color, + timer_bucket_origin_x - bucket_length - 0.01, + timer_bucket_origin_y - bucket_length + 0.05, + bucket_length + 0.03, + 0.075); + } + + //Draw external source pipe + fillSceneRect( g2d, + spout_color, + intake_bucket_origin_x - bucket_length/4, + intake_bucket_origin_y + 0.8, + 7, + spout_width); + + if(input_flow > 0) { + fillSceneRect( g2d, + water_color, + intake_bucket_origin_x - bucket_length/4 - flow_width + 0.03, + intake_bucket_origin_y + 0.8 - spout_width/2, + flow_width, + 0.815 + bucket_length - spout_width/2); + } + + //Draw float + double float_base_height = 0.25; + fillSceneRect( g2d, + float_color, + timer_bucket_origin_x - bucket_length + bucket_length/4, + timer_bucket_origin_y - timer_offset + float_base_height, + bucket_length/2, + 0.25); + + double float_arm_origin_x = timer_bucket_origin_x - bucket_length + bucket_length * 0.45; + double float_arm_origin_y = timer_bucket_origin_y - timer_offset + clock_float_height + float_base_height; + fillSceneRect( g2d, + float_color, + float_arm_origin_x, + float_arm_origin_y, + bucket_length*0.1, + clock_float_height); + + double tooth_ratio = 2.25 * tooth.y[3]; + for(double ii = bucket_length/2.0; ii < (clock_float_height) ; ii += tooth_ratio) { + fillScenePoly(g2d, tooth, 0.0, float_arm_origin_x, ii + float_arm_origin_y - clock_float_height); + } + + //Draw Gear + double clock_origin_x = float_arm_origin_x - 1.85; + double clock_origin_y = 2.0; + double clock_diam = 2.5; + double gear_x = clock_origin_x + 0.85; + double gear_y = clock_origin_y; + double gear_width = 1.5; + double gear_noise = 0.3; //initial gear rotational offset + gear = new ScenePoly(); + gear.x = new double[] { 0, 0, 0, 0, 0}; + gear.y = new double[] { 0, 0, 0, 0, 0}; + gear.n = 5; + for(int ii = 0; ii < gear.n; ++ii) { + gear.x[ii] = tooth.x[ii]-(gear_width*0.5); + gear.y[ii] = tooth.y[ii]; + } + gear.n = 5; + double gear_circ = (Math.PI * (gear_width - (2*tooth.x[2]))); + int gear_count = (int)(gear_circ / tooth_ratio); + double gear_offset = ((timer_capacity * bucket_length) / gear_circ) * 2 * Math.PI; + gear_offset *= 3; //I don't know why, but this magic number makes the gear animation sync with the rack + gear.color = gear_color; + for(int ii = 0; ii < gear_count; ++ii) { + fillScenePoly(g2d, gear, (ii + gear_noise + gear_offset) * (360/gear_count) * (Math.PI/180), gear_x, gear_y); + } + fillSceneOval ( g2d, + gear_color, + gear_x, + gear_y, + gear_width*1.05, + gear_width*1.05); + + //Draw Clock + fillSceneOval ( g2d, + clock_color, + clock_origin_x, + clock_origin_y, + clock_diam, + clock_diam); + + double clock_display_length = 1.0; + double clock_display_origin_x = clock_origin_x - clock_display_length/2.0; + double clock_display_origin_y = clock_origin_y; + fillSceneRect( g2d, + clock_display_color, + clock_display_origin_x, + clock_display_origin_y, + clock_display_length, + clock_display_length); + + g2d.setFont(new Font("", Font.PLAIN, 24)); + g2d.setPaint(tick_color); + g2d.drawString ( String.format("%02d",current_tick), (int)(worldOriginX+scale*(clock_display_origin_x + clock_display_length*0.25)), (int)(worldOriginY-scale*(clock_display_origin_y - clock_display_length*0.6))); + + // Draw Information + g2d.setPaint(Color.BLACK); + g2d.setFont(new Font("", Font.PLAIN, 12)); + int string_height = 220; + g2d.drawString ( String.format("Input Flow Rate: [%.4f] cm^3/s",input_flow), 20,string_height+=20); + g2d.drawString ( String.format("Intake Water Level: [%.4f] cm",intake_lvl), 20,string_height+=20); + g2d.drawString ( String.format("Intake Water Volume: [%.4f] cm^3",intake_vol), 20,string_height+=20); + g2d.drawString ( String.format("Intake Overflow Rate: [%.4f] cm^3/s",overflow_rate), 20,string_height+=20); + g2d.drawString ( String.format("Intake Spout Rate: [%.4f] cm^3/s",spout_rate), 20,string_height+=20); + g2d.drawString ( String.format("Timer Water Level: [%.4f] cm",timer_lvl), 20,string_height+=20); + g2d.drawString ( String.format("Timer Water Volume: [%.4f] cm^3",timer_vol), 20,string_height+=20); + g2d.drawString ( String.format("Current Time Tick: [%d]",current_tick), 20,string_height+=20); + } + + @Override + public void paintComponent(Graphics g) { + super.paintComponent(g); + doDrawing(g); + } +} + +class TrickSimMode { + public static final int INIT = 0; + public static final int FREEZE = 1; + public static final int RUN = 5; +} + +class InputFlowCtrlPanel extends JPanel implements ChangeListener { + + static final int FLOW_MIN = 0; + static final int FLOW_MAX = 10000; + static final int FLOW_INIT = 1000; + + private RangeView rangeView; + private JSlider inputFlowSlider; + + public InputFlowCtrlPanel (RangeView view) { + rangeView = view; + setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); + + JLabel sliderLabel = new JLabel("", JLabel.CENTER); + sliderLabel.setAlignmentX(CENTER_ALIGNMENT); + + inputFlowSlider = new JSlider(JSlider.HORIZONTAL, FLOW_MIN, FLOW_MAX, FLOW_INIT); + inputFlowSlider.addChangeListener(this); + inputFlowSlider.setToolTipText("Input Flow Rate (cm^3/s)."); + inputFlowSlider.setMajorTickSpacing(1000); + inputFlowSlider.setMinorTickSpacing(100); + inputFlowSlider.setPaintTicks(true); + inputFlowSlider.setPaintLabels(true); + + add(sliderLabel); + add(inputFlowSlider); + } + + @Override + public void stateChanged(ChangeEvent e) { + JSlider source = (JSlider)e.getSource(); + if (!source.getValueIsAdjusting()) { + rangeView.setInputFlowSelect( source.getValue()); + rangeView.new_input_flow = true; + } + } + + public void setValue(int value) { + if (value > FLOW_MAX) value = FLOW_MAX; + if (value < FLOW_MIN) value = FLOW_MIN; + inputFlowSlider.setValue(value); + } +} + +class ControlPanel extends JPanel implements ActionListener { + + private RangeView rangeView; + private InputFlowCtrlPanel inputFlowCtrlPanel; + + public ControlPanel(RangeView view) { + + rangeView = view; + setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); + + JPanel labeledInputFlowCtrlPanel = new JPanel(); + labeledInputFlowCtrlPanel.setLayout(new BoxLayout(labeledInputFlowCtrlPanel, BoxLayout.Y_AXIS)); + JLabel inputFlowCtrlLabel = new JLabel("Input Flow Rate (cm^3/s)"); + inputFlowCtrlLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + labeledInputFlowCtrlPanel.add(inputFlowCtrlLabel); + inputFlowCtrlPanel = new InputFlowCtrlPanel(rangeView); + labeledInputFlowCtrlPanel.add( inputFlowCtrlPanel ); + add(labeledInputFlowCtrlPanel); + + } + + public void actionPerformed(ActionEvent e) { + String s = e.getActionCommand(); + switch (s) { + default: + System.out.println("Unknown Action Command:" + s); + break; + } + } +} // class ControlPanel + +public class WaterClockDisplay extends JFrame { + + private RangeView rangeView; + private BufferedReader in; + private DataOutputStream out; + private JPanel panelGroup0; + private JPanel panelGroup1; + private ControlPanel controlPanel; + + public WaterClockDisplay(RangeView arena) { + setTitle("Water Clock"); + + rangeView = arena; + + panelGroup1 = new JPanel(); + panelGroup1.setLayout(new BoxLayout(panelGroup1, BoxLayout.X_AXIS)); + panelGroup1.add(rangeView); + + controlPanel = new ControlPanel(rangeView); + + panelGroup0 = new JPanel(); + panelGroup0.setLayout(new BoxLayout(panelGroup0, BoxLayout.Y_AXIS)); + panelGroup0.add(panelGroup1); + panelGroup0.add(controlPanel); + + add(panelGroup0); + + rangeView.setScale(64); + + setSize(800, 500); + setLocationRelativeTo(null); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setFocusable(true); + + } + + public void connectToServer(String host, int port ) throws IOException { + Socket socket = new Socket(host, port); + in = new BufferedReader( new InputStreamReader( socket.getInputStream())); + out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())); + } + + public void drawRangeView() { + rangeView.repaint(); + } + + private static void printHelpText() { + System.out.println( + "----------------------------------------------------------------------\n" + + "usage: java jar WaterClockDisplay.jar \n" + + "----------------------------------------------------------------------\n" + ); + } + + public enum ModelState { INACTIVE, READY, ACTIVE } + + public static void main(String[] args) throws IOException, InterruptedException { + + String host = "localHost"; + int port = 0; + boolean boom = false; + + int ii = 0; + while (ii < args.length) { + switch (args[ii]) { + case "-help" : + case "--help" : { + printHelpText(); + System.exit(0); + } break; + default : { + port = (Integer.parseInt(args[ii])); + } break; + } + ++ii; + } + + boolean go = true; + double dt = 0.100; // Time between updates (seconds). + double spout_rate = 0.0; + double overflow_rate = 0.0; + double intake_depth = 0.0; + double timer_depth = 0.0; + double intake_lvl = 0.0; + double timer_lvl = 0.0; + double intake_vol = 0.0; + double timer_vol = 0.0; + double spout_height = 0.0; + double overflow_height = 0.0; + double input_flow = 0.0; + double flow_select = 0.0; + int tick = 0; + + // Outbound command variables + int simMode = 0; + boolean standalone = false; + + int mapScale = 32 ; // pixels per meter. + + RangeView rangeView = new RangeView( mapScale); + WaterClockDisplay waterClockDisplay = new WaterClockDisplay( rangeView); + waterClockDisplay.setVisible(true); + waterClockDisplay.drawRangeView(); + + if (go) { + if (port == 0) { + System.out.println("No variable server port specified."); + printHelpText(); + System.exit(0); + } + + // Connect to the Trick simulation's variable server + System.out.println("Connecting to: " + host + ":" + port); + waterClockDisplay.connectToServer(host, port); + + waterClockDisplay.out.writeBytes("trick.var_set_client_tag(\"WaterClockDisplay\") \n"); + waterClockDisplay.out.flush(); + + // Have the Variable Server send us the simulation mode ONCE. + waterClockDisplay.out.writeBytes( "trick.var_add(\"trick_sys.sched.mode\")\n" + + "trick.var_send() \n" + + "trick.var_clear() \n"); + waterClockDisplay.out.flush(); + + // Read the response and extract the simulation mode. + try { + String line; + String field[]; + line = waterClockDisplay.in.readLine(); + field = line.split("\t"); + simMode = Integer.parseInt( field[1]); + } catch (IOException | NullPointerException e ) { + go = false; + } + + // Configure the Variable Server to cyclically send us the following varibales. + // Tell the variable server: + // 1) We want the values of the following variables: + waterClockDisplay.out.writeBytes( "trick.var_pause() \n" + + "trick.var_add(\"dyn.waterclock.intake_clock_spout_flowrate\")\n" + + "trick.var_add(\"dyn.waterclock.intake_overflow_flowrate\")\n" + + "trick.var_add(\"dyn.waterclock.intake_bucket_depth\")\n" + + "trick.var_add(\"dyn.waterclock.timer_bucket_depth\")\n" + + "trick.var_add(\"dyn.waterclock.intake_water_level\")\n" + + "trick.var_add(\"dyn.waterclock.timer_water_level\")\n" + + "trick.var_add(\"dyn.waterclock.intake_bucket_vol\")\n" + + "trick.var_add(\"dyn.waterclock.timer_bucket_vol\")\n" + + "trick.var_add(\"dyn.waterclock.intake_clock_spout_height\")\n" + + "trick.var_add(\"dyn.waterclock.intake_overflow_height\")\n" + + "trick.var_add(\"dyn.waterclock.input_flow\")\n" + + "trick.var_add(\"dyn.waterclock.current_tick\")\n" + + "trick.var_add(\"trick_sys.sched.mode\")\n" + + // 2) We want the responses in ASCII: + "trick.var_ascii() \n" + + // 3) We want values to be updated at the specified rate: + String.format("trick.var_cycle(%.3f)\n", dt) + + // 4) Start sending values as specified. + "trick.var_unpause() \n" ); + waterClockDisplay.out.flush(); + } // if go + + while (go) { + + // Recieve and parse periodic data response from the variable server. + try { + String line; + String field[]; + line = waterClockDisplay.in.readLine(); + field = line.split("\t"); + spout_rate = Double.parseDouble( field[1]); + overflow_rate = Double.parseDouble( field[2]); + intake_depth = Double.parseDouble( field[3]); + timer_depth = Double.parseDouble( field[4]); + intake_lvl = Double.parseDouble( field[5]); + timer_lvl = Double.parseDouble( field[6]); + intake_vol = Double.parseDouble( field[7]); + timer_vol = Double.parseDouble( field[8]); + spout_height = Double.parseDouble( field[9]); + overflow_height = Double.parseDouble( field[10]); + input_flow = Double.parseDouble( field[11]); + tick = Integer.parseInt( field[12]); + simMode = Integer.parseInt( field[13]); + } catch (IOException | NullPointerException e ) { + go = false; + } + + // Update the display data. + rangeView.setSpoutRate(spout_rate); + rangeView.setOverflowRate(overflow_rate); + rangeView.setIntakeDepth(intake_depth); + rangeView.setTimerDepth(timer_depth); + rangeView.setIntakeWarerLevel(intake_lvl); + rangeView.setTimerWarerLevel(timer_lvl); + rangeView.setIntakeWaterVol(intake_vol); + rangeView.setTimerWaterLevel(timer_vol); + rangeView.setSpoutHeight(spout_height); + rangeView.setOverflowHeight(overflow_height); + rangeView.setInputFlow(input_flow); + rangeView.setCurrentTick(tick); + + if(rangeView.new_input_flow) { + flow_select = rangeView.getInputFlowSelect(); + waterClockDisplay.out.writeBytes( String.format("dyn.waterclock.input_flow = %f ;\n", flow_select )); + rangeView.new_input_flow = false; + } + + waterClockDisplay.out.flush(); + + // Update the scene. + waterClockDisplay.drawRangeView(); + + } // while + } // main +} // class diff --git a/trick_sims/SIM_life/models/life/include/BodyPart.hh b/trick_sims/SIM_life/models/life/include/BodyPart.hh new file mode 100644 index 00000000..42bc34ac --- /dev/null +++ b/trick_sims/SIM_life/models/life/include/BodyPart.hh @@ -0,0 +1,17 @@ + +#include "Shape.hh" + +/* +A body part of an organism +*/ +class BodyPart: public Shape +{ + private: + + public: + + BodyPart(); + + ~BodyPart(); + +}; diff --git a/trick_sims/SIM_life/models/life/include/Entity.hh b/trick_sims/SIM_life/models/life/include/Entity.hh new file mode 100644 index 00000000..d3536738 --- /dev/null +++ b/trick_sims/SIM_life/models/life/include/Entity.hh @@ -0,0 +1,14 @@ + +/* +Abstract base class for anything that exists on the map and can interact/be interacted with +*/ +class Entity +{ + private: + + public: + + virtual Shape* get_shapes() = 0; // Return root of shape tree + virtual int move(int x, int y) = 0; // Translates entire entity + virtual int rotate(int d) = 0; // Rotates entire entity around core shape origin +} diff --git a/trick_sims/SIM_life/models/life/include/Organism.hh b/trick_sims/SIM_life/models/life/include/Organism.hh new file mode 100644 index 00000000..7fce4936 --- /dev/null +++ b/trick_sims/SIM_life/models/life/include/Organism.hh @@ -0,0 +1,23 @@ + +#include "Entity.hh" +#include "Shape.hh" + +/* +An organism +*/ +class Organism: public Entity +{ + private: + + BodyPart* body; // Tree of body parts + + public: + + //Organism(BodyPart* parts); + + ~Organism(); + + Shape* get_shapes(); // Return root of shape tree + int move(int x, int y); // Translates entire entity + int rotate(int d); // Rotates entire entity around core shape origin +} diff --git a/trick_sims/SIM_life/models/life/include/Shape.hh b/trick_sims/SIM_life/models/life/include/Shape.hh new file mode 100644 index 00000000..94c9334e --- /dev/null +++ b/trick_sims/SIM_life/models/life/include/Shape.hh @@ -0,0 +1,49 @@ + +#include "Structs/Coordinate.hh" +#include "Structs/Color.hh" + +enum Shape_t +{ + S_CIRCLE = 0, + S_TRIANGLE = 1, + S_RECTANGLE = 2 +}; + +/* +Abstract base representation of a single geometric unit +*/ +class Shape +{ + private: + + Coord pos; // Center of the shape + Shape_t shape; // Type of shape + Shape* parent; // Parent shape. Null if core shape + Shape** attached_shapes; // Shapes attached to this shape + uint8_t attached_shapes_count; // How many shapes are attached + Color color; // Base color of this shape + //Some way to indicate attach point to parent + + public: + + Shape(); + + virtual ~Shape() = 0; + + // Simple move function that translates position directly, no checks + virtual void move(int x, int y); + + // Rotate by d degrees around this origin + virtual void rotate(int d); + + // Rotate by d degrees around point c + virtual void rotate(int d, Coord c); + + Coord get_coord(); + Shape_t get_shape_type(); + Shape* get_shapes(); + uint8_t get_shape_count(); + Color get_color; + + +}; diff --git a/trick_sims/SIM_life/models/life/include/Structs/Color.hh b/trick_sims/SIM_life/models/life/include/Structs/Color.hh new file mode 100644 index 00000000..3c476333 --- /dev/null +++ b/trick_sims/SIM_life/models/life/include/Structs/Color.hh @@ -0,0 +1,11 @@ +#include "stdint.h." + +/* +Coordinate struct +*/ +struct Color +{ + uint8_t r; + uint8_t b; + uint8_t g; +}; diff --git a/trick_sims/SIM_life/models/life/include/Structs/Coordinate.hh b/trick_sims/SIM_life/models/life/include/Structs/Coordinate.hh new file mode 100644 index 00000000..0bc8eab5 --- /dev/null +++ b/trick_sims/SIM_life/models/life/include/Structs/Coordinate.hh @@ -0,0 +1,9 @@ + +/* +Coordinate struct. Map units are tracked in ints +*/ +struct Coord +{ + int x; + int y; +};