mirror of
https://github.com/nasa/trick.git
synced 2024-12-19 21:27:54 +00:00
Hot-air balloon simulation. #1210
This commit is contained in:
parent
dbf465f217
commit
b643296fd8
10
trick_sims/SIM_balloon/Modified_data/realtime.py
Executable file
10
trick_sims/SIM_balloon/Modified_data/realtime.py
Executable file
@ -0,0 +1,10 @@
|
||||
|
||||
trick.real_time_enable()
|
||||
trick.exec_set_software_frame(0.1)
|
||||
trick.itimer_enable()
|
||||
|
||||
trick.exec_set_enable_freeze(True)
|
||||
trick.exec_set_freeze_command(True)
|
||||
|
||||
simControlPanel = trick.SimControlPanel()
|
||||
trick.add_external_application(simControlPanel)
|
24
trick_sims/SIM_balloon/RUN_test/input.py
Normal file
24
trick_sims/SIM_balloon/RUN_test/input.py
Normal file
@ -0,0 +1,24 @@
|
||||
execfile("Modified_data/realtime.py")
|
||||
|
||||
dyn.balloon.pos[0] = 0
|
||||
#dyn.balloon.pos[1] = 136.89
|
||||
dyn.balloon.vel[0] = 0.0
|
||||
dyn.balloon.vel[1] = 0.0
|
||||
dyn.balloon.envelope_air_temperature = 92.0
|
||||
|
||||
# ==========================================
|
||||
# Start the Satellite Graphics Client
|
||||
# ==========================================
|
||||
varServerPort = trick.var_server_get_port();
|
||||
BalloonDisplay_path = "models/graphics/dist/BalloonDisplay.jar"
|
||||
|
||||
if (os.path.isfile(BalloonDisplay_path)) :
|
||||
BalloonDisplay_cmd = "java -jar " \
|
||||
+ BalloonDisplay_path \
|
||||
+ " " + str(varServerPort) + " &" ;
|
||||
print(BalloonDisplay_cmd)
|
||||
os.system( BalloonDisplay_cmd);
|
||||
else :
|
||||
print('==================================================================================')
|
||||
print('BalloonDisplay needs to be built. Please \"cd\" into ../models/graphics and type \"make\".')
|
||||
print('==================================================================================')
|
30
trick_sims/SIM_balloon/S_define
Normal file
30
trick_sims/SIM_balloon/S_define
Normal file
@ -0,0 +1,30 @@
|
||||
/************************************************************
|
||||
PURPOSE:
|
||||
( Simulate a hot-air balloon. )
|
||||
LIBRARY DEPENDENCIES:
|
||||
((balloon/src/Balloon.cpp)
|
||||
(atmosphere/src/atmosphere.c))
|
||||
*************************************************************/
|
||||
#include "sim_objects/default_trick_sys.sm"
|
||||
##include "balloon/include/Balloon.hh"
|
||||
|
||||
class BalloonSimObject : public Trick::SimObject {
|
||||
public:
|
||||
Balloon balloon;
|
||||
|
||||
BalloonSimObject() {
|
||||
("default_data") balloon.default_data() ;
|
||||
("initialization") balloon.state_init() ;
|
||||
("derivative") balloon.state_deriv() ;
|
||||
(0.1, "scheduled") balloon.control() ;
|
||||
("integration") trick_ret = balloon.state_integ() ;
|
||||
("post_integration") balloon.check_ground_contact() ;
|
||||
}
|
||||
};
|
||||
|
||||
BalloonSimObject dyn;
|
||||
IntegLoop dyn_integloop(0.1) dyn;
|
||||
|
||||
void create_connections() {
|
||||
dyn_integloop.getIntegrator(Runge_Kutta_4, 4);
|
||||
}
|
2
trick_sims/SIM_balloon/S_overrides.mk
Normal file
2
trick_sims/SIM_balloon/S_overrides.mk
Normal file
@ -0,0 +1,2 @@
|
||||
TRICK_CFLAGS += -Imodels
|
||||
TRICK_CXXFLAGS += -Imodels
|
@ -0,0 +1,24 @@
|
||||
#ifndef ATMOSPHERE_H
|
||||
#define ATMOSPHERE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Returns atmospheric density (kg/m^3) at the given altitude (m).*/
|
||||
double US_STD_density ( double alt_m );
|
||||
|
||||
/* Returns acceleration of gravity (m/s^2) at the given altitude (m).*/
|
||||
double US_STD_gravity( double alt_m);
|
||||
|
||||
/* Returns atmospheric temperature (℃) at the given altitude (m).*/
|
||||
double US_STD_temperature( double alt_m );
|
||||
|
||||
/* Returns atmospheric pressure (pascals) at the given altitude (m).*/
|
||||
double US_STD_pressure( double alt_m);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
71
trick_sims/SIM_balloon/models/atmosphere/src/atmosphere.c
Executable file
71
trick_sims/SIM_balloon/models/atmosphere/src/atmosphere.c
Executable file
@ -0,0 +1,71 @@
|
||||
#include <stdio.h>
|
||||
|
||||
static double interpolate( double x, const double xa[], const double fa[], int N_elems ) {
|
||||
int ii;
|
||||
for (ii=0 ; ((ii+2 < N_elems ) && (x > xa[ii+1])) ; ii++ ) ;
|
||||
double x_lower = xa[ii];
|
||||
double x_upper = xa[ii+1];
|
||||
double f_lower = fa[ii];
|
||||
double f_upper = fa[ii+1];
|
||||
if (x < x_lower) {
|
||||
fprintf(stderr, "Interpolation x is out of range low.\n");
|
||||
return(f_lower);
|
||||
}
|
||||
if (x > x_upper) {
|
||||
fprintf(stderr, "Interpolation x is out of range high.\n");
|
||||
return(f_upper);
|
||||
}
|
||||
double f = (x_upper - x)/(x_upper - x_lower) * f_lower +
|
||||
(x - x_lower)/(x_upper - x_lower) * f_upper ;
|
||||
return(f);
|
||||
}
|
||||
|
||||
#define NUM_ELEMENTS 21
|
||||
// Units = meters (above sea level).
|
||||
const double altitude_array[NUM_ELEMENTS] = {
|
||||
-1000.0, 0.0, 1000.0, 2000.0, 3000.0, 4000.0, 5000.0, 6000.0,
|
||||
7000.0, 8000.0, 9000.0, 10000.0, 15000.0, 20000.0, 25000.0, 30000.0,
|
||||
40000.0, 50000.0, 60000.0, 70000.0, 80000.0 };
|
||||
|
||||
// Units = kilograms per cubic meter.
|
||||
const double US_STD_density_array[NUM_ELEMENTS] = {
|
||||
1.347, 1.225, 1.112, 1.007, 0.9093, 0.8194, 0.7364, 0.6601,
|
||||
0.5900, 0.5258, 0.4671, 0.4135, 0.1948, 0.08891, 0.04008, 0.01841,
|
||||
0.003996, 0.001027, 0.0003097, 0.00008283, 0.00001846 };
|
||||
|
||||
// Units = meters per second squared.
|
||||
const double US_STD_gravity_array[NUM_ELEMENTS] = {
|
||||
9.810, 9.807, 9.804, 9.801, 9.797, 9.794, 9.791, 9.788,
|
||||
9.785, 9.782, 9.779, 9.776, 9.761, 9.745, 9.730, 9.715,
|
||||
9.684, 9.654, 9.624, 9.594, 9.564
|
||||
};
|
||||
|
||||
// Units = celsius
|
||||
const double US_STD_temperature_array[NUM_ELEMENTS] = {
|
||||
21.50, 15.00, 8.50, 2.00, -4.49, -10.98, -17.47, -23.96,
|
||||
-30.45, -36.94, -43.42, -49.90, -56.50, -56.50, -51.60, -46.64,
|
||||
-22.80, -2.5, -26.13, -53.57, -74.51
|
||||
};
|
||||
|
||||
// Units = pascals
|
||||
const double US_STD_pressure_array[NUM_ELEMENTS] = {
|
||||
113900.0, 101325.0, 89880.0, 79500.0, 70120.0, 61660.0, 54050.0, 47220.0,
|
||||
41110.0, 35650.0, 30800.0, 26500.0, 12110.0, 5529.0, 2549.0, 1197.0,
|
||||
287.00, 79.78, 21.96, 5.20, 1.10
|
||||
};
|
||||
|
||||
double US_STD_density ( double alt_m ) {
|
||||
return interpolate( alt_m, altitude_array, US_STD_density_array, NUM_ELEMENTS );
|
||||
}
|
||||
|
||||
double US_STD_gravity( double alt_m) {
|
||||
return interpolate( alt_m, altitude_array, US_STD_gravity_array, NUM_ELEMENTS );
|
||||
}
|
||||
|
||||
double US_STD_temperature( double alt_m ) {
|
||||
return interpolate( alt_m, altitude_array, US_STD_temperature_array, NUM_ELEMENTS );
|
||||
}
|
||||
|
||||
double US_STD_pressure( double alt_m) {
|
||||
return interpolate( alt_m, altitude_array, US_STD_pressure_array, NUM_ELEMENTS );
|
||||
}
|
49
trick_sims/SIM_balloon/models/balloon/include/Balloon.hh
Executable file
49
trick_sims/SIM_balloon/models/balloon/include/Balloon.hh
Executable file
@ -0,0 +1,49 @@
|
||||
/************************************************************************
|
||||
PURPOSE: (Simulate a hor-air balloon.)
|
||||
LIBRARY DEPENDENCIES:
|
||||
((balloon/src/Balloon.o))
|
||||
**************************************************************************/
|
||||
#ifndef BALLOON_HH
|
||||
#define BALLOON_HH
|
||||
|
||||
class Balloon {
|
||||
public:
|
||||
// State Variables (Uncalculated Variables)
|
||||
double pos[2];
|
||||
double vel[2];
|
||||
double envelope_mass;
|
||||
double basket_mass;
|
||||
double burner_system_mass;
|
||||
double payload_mass;
|
||||
double envelope_air_temperature;
|
||||
double envelope_radius;
|
||||
double envelope_theta;
|
||||
double Cd;
|
||||
|
||||
// Calculated Variables
|
||||
double acc[2];
|
||||
double envelope_volume;
|
||||
double fixed_mass;
|
||||
|
||||
// Control Variable
|
||||
int temperature_change_command;
|
||||
|
||||
// Methods
|
||||
int default_data();
|
||||
int state_init();
|
||||
int state_deriv();
|
||||
int state_integ();
|
||||
int check_ground_contact();
|
||||
int control();
|
||||
double calc_fixed_mass();
|
||||
double calc_envelope_volume();
|
||||
double calc_total_mass();
|
||||
double calc_envelope_air_mass();
|
||||
double calc_heated_air_density();
|
||||
double calc_buoyancy_force();
|
||||
double calc_displaced_air_mass();
|
||||
double calc_drag_force();
|
||||
double volume_of_a_spherical_dome( double r, double h);
|
||||
double volume_of_a_cone( double r, double h);
|
||||
};
|
||||
#endif
|
134
trick_sims/SIM_balloon/models/balloon/src/Balloon.cpp
Executable file
134
trick_sims/SIM_balloon/models/balloon/src/Balloon.cpp
Executable file
@ -0,0 +1,134 @@
|
||||
/********************************* TRICK HEADER *******************************
|
||||
PURPOSE: ( Simulate a hot-air balloon. )
|
||||
LIBRARY DEPENDENCY:
|
||||
((Balloon.o))
|
||||
*******************************************************************************/
|
||||
#include "balloon/include/Balloon.hh"
|
||||
#include "atmosphere/include/atmosphere.h"
|
||||
|
||||
#include "trick/integrator_c_intf.h"
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <iostream>
|
||||
|
||||
int Balloon::default_data() {
|
||||
|
||||
pos[0] = 0.0;
|
||||
pos[1] = 2.0;
|
||||
vel[0] = 0.0;
|
||||
vel[1] = 0.0;
|
||||
|
||||
envelope_mass = 113.4;
|
||||
basket_mass = 63.5;
|
||||
burner_system_mass = 206.4;
|
||||
payload_mass = 300.0;
|
||||
|
||||
envelope_air_temperature = 80;
|
||||
envelope_radius = 8.5;
|
||||
envelope_theta = 45 * (M_PI/180.0);
|
||||
|
||||
Cd = 0.5;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int Balloon::state_init() {
|
||||
envelope_volume = calc_envelope_volume();
|
||||
fixed_mass = calc_fixed_mass();
|
||||
return (0);
|
||||
}
|
||||
|
||||
int Balloon::state_deriv() {
|
||||
double total_mass = calc_total_mass();
|
||||
double F_gravity = total_mass * (-US_STD_gravity( pos[1])); /* Equation #2 */
|
||||
double F_buoyancy = calc_buoyancy_force();
|
||||
double F_drag = calc_drag_force();
|
||||
acc[0] = 0.0;
|
||||
acc[1] = (F_gravity + F_buoyancy + F_drag) / total_mass; /* Equation #1 */
|
||||
return(0);
|
||||
}
|
||||
|
||||
int Balloon::state_integ() {
|
||||
int integration_step;
|
||||
load_state ( &pos[0], &pos[1], &vel[0], &vel[1], (double*)0);
|
||||
load_deriv ( &vel[0], &vel[1], &acc[0], &acc[1], (double*)0);
|
||||
integration_step = integrate();
|
||||
unload_state( &pos[0], &pos[1], &vel[0], &vel[1], (double*)0);
|
||||
return(integration_step);
|
||||
}
|
||||
|
||||
double Balloon::calc_total_mass() {
|
||||
return (fixed_mass + calc_envelope_air_mass());
|
||||
}
|
||||
|
||||
double Balloon::calc_envelope_air_mass() {
|
||||
double heated_air_density = calc_heated_air_density();
|
||||
return ( heated_air_density * envelope_volume ); /* Equation #4 with density of heated air. */
|
||||
}
|
||||
|
||||
double Balloon::calc_envelope_volume() {
|
||||
double h;
|
||||
|
||||
h = envelope_radius * (1.0 + sin( envelope_theta));
|
||||
double v_dome = volume_of_a_spherical_dome(envelope_radius, h);
|
||||
|
||||
double r = envelope_radius * cos(envelope_theta);
|
||||
h = r / tan(envelope_theta);
|
||||
double v_cone = volume_of_a_cone(r, h);
|
||||
|
||||
return (v_dome + v_cone); /* Equation #7 */
|
||||
}
|
||||
|
||||
double Balloon::volume_of_a_spherical_dome( double r, double h) {
|
||||
return (M_PI*((r*h*h)-((h*h*h)/3.0))); /* Equation #5 */
|
||||
}
|
||||
|
||||
double Balloon::volume_of_a_cone( double r, double h) {
|
||||
return ((M_PI*r*r*h)/3.0); /* Equation #6 */
|
||||
}
|
||||
|
||||
double Balloon::calc_heated_air_density() {
|
||||
double t_k = envelope_air_temperature + 273.15;
|
||||
double rho = US_STD_pressure(pos[1]) / (287.055 * t_k); /* Equation #8 */
|
||||
return rho;
|
||||
}
|
||||
|
||||
double Balloon::calc_buoyancy_force() {
|
||||
return( calc_displaced_air_mass() * US_STD_gravity( pos[1])); /* Equation 9 */
|
||||
}
|
||||
|
||||
double Balloon::calc_displaced_air_mass() {
|
||||
return( US_STD_density(pos[1]) * envelope_volume); /* Equation #4 with standard air density. */
|
||||
}
|
||||
|
||||
double Balloon::calc_fixed_mass() {
|
||||
return (envelope_mass + basket_mass + burner_system_mass + payload_mass);
|
||||
}
|
||||
|
||||
double Balloon::calc_drag_force() {
|
||||
|
||||
double A = M_PI * envelope_radius * envelope_radius; /* Equation 11 */
|
||||
return (- Cd * 0.5 * US_STD_density(pos[1]) * abs(vel[1]) * vel[1] * A); /* Equation 10 */
|
||||
}
|
||||
|
||||
int Balloon::control() {
|
||||
if ( temperature_change_command != 0) {
|
||||
envelope_air_temperature += temperature_change_command;
|
||||
}
|
||||
if (envelope_air_temperature > 120.0) {
|
||||
envelope_air_temperature = 120.0;
|
||||
}
|
||||
if (envelope_air_temperature < 80.0) {
|
||||
envelope_air_temperature = 80.0;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int Balloon::check_ground_contact() {
|
||||
if (pos[1] < 2.0) {
|
||||
pos[1] = 2.0;
|
||||
vel[0] = 0.0;
|
||||
vel[1] = 0.0;
|
||||
}
|
||||
return(0);
|
||||
}
|
598
trick_sims/SIM_balloon/models/graphics/src/BalloonDisplay.java
Executable file
598
trick_sims/SIM_balloon/models/graphics/src/BalloonDisplay.java
Executable file
@ -0,0 +1,598 @@
|
||||
/*
|
||||
* Trick
|
||||
* 2021 (c) National Aeronautics and Space Administration (NASA)
|
||||
*/
|
||||
|
||||
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 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;
|
||||
/**
|
||||
*
|
||||
* @author penn
|
||||
*/
|
||||
|
||||
class ScenePoly {
|
||||
public Color color;
|
||||
public int n;
|
||||
public double[] x;
|
||||
public double[] y;
|
||||
}
|
||||
|
||||
class RangeView extends JPanel {
|
||||
|
||||
private int scale;
|
||||
private Color skyColor;
|
||||
private Color groundColor;
|
||||
private Color envelope_color_1;
|
||||
private Color envelope_color_2;
|
||||
private Color basket_color;
|
||||
private Color envelope_phong;
|
||||
|
||||
// Origin of world coordinates in jpanel coordinates.
|
||||
private int worldOriginX;
|
||||
private int worldOriginY;
|
||||
|
||||
private double[] balloonPos;
|
||||
private double[] balloonVel;
|
||||
private int envelopeAirTemp; /* degrees C */
|
||||
private double envelope_radius;
|
||||
private double envelope_theta;
|
||||
|
||||
private ScenePoly cone;
|
||||
private ScenePoly upright; // The frame that connects the basket, burner, and balloon
|
||||
private ScenePoly basket;
|
||||
|
||||
private int[] workPolyX, workPolyY;
|
||||
|
||||
// Controls
|
||||
private int deltaTemp ;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*/
|
||||
public RangeView( int mapScale) {
|
||||
|
||||
setScale(mapScale);
|
||||
|
||||
deltaTemp = 0;
|
||||
|
||||
skyColor = new Color(184,202,231);
|
||||
groundColor = new Color(100,140, 60);
|
||||
|
||||
balloonPos = new double[]
|
||||
{0.0, 2.0};
|
||||
balloonVel = new double[]
|
||||
{0.0, 0.0};
|
||||
|
||||
envelope_color_1 = new Color(254,181, 36);
|
||||
envelope_color_2 = new Color(251, 0, 21);
|
||||
basket_color = new Color(220,180,120);
|
||||
envelope_phong = new Color(220,220,220,80);
|
||||
|
||||
envelope_radius = 8.5;
|
||||
envelope_theta = Math.toRadians(45.0);
|
||||
|
||||
envelopeAirTemp = 0;
|
||||
|
||||
cone = new ScenePoly();
|
||||
cone.color = envelope_color_1;
|
||||
cone.x = new double[4];
|
||||
cone.y = new double[4];
|
||||
cone.n = 4;
|
||||
|
||||
upright = new ScenePoly();
|
||||
upright.color = Color.BLACK;
|
||||
upright.x = new double[] {-0.40, 0.40, 0.50, 0.40, 0.30,-0.30,-0.40,-0.50};
|
||||
upright.y = new double[] { 0.00, 0.00,-1.00,-1.00,-0.10,-0.10,-1.00,-1.00};
|
||||
upright.n = 8;
|
||||
|
||||
basket = new ScenePoly();
|
||||
basket.color = basket_color;
|
||||
basket.x = new double[] {-0.50, 0.50, 0.50,-0.50};
|
||||
basket.y = new double[] {-1.00,-1.00,-2.00,-2.00};
|
||||
basket.n = 4;
|
||||
|
||||
workPolyX = new int[30];
|
||||
workPolyY = new int[30];
|
||||
}
|
||||
|
||||
// |jpanel_x| = |origin_x| + |scale 0 | * |cos(angle) -sin(angle)| * |world_x|
|
||||
// |jpanel_y| |origin_y| | 0 -scale| |sin(angle) cos(angle)| |world_y|
|
||||
|
||||
public void drawScenePoly(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 drawSceneOval(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 incTemperature() { deltaTemp = 1; }
|
||||
public void decTemperature() { deltaTemp = -1; }
|
||||
public void resetDeltaTemp() { deltaTemp = 0; }
|
||||
public int getDeltaTemp() { return deltaTemp; }
|
||||
|
||||
public void setballoonPos(double x, double y) {
|
||||
balloonPos[0] = x;
|
||||
balloonPos[1] = y;
|
||||
}
|
||||
public void setBalloonVel(double vx, double vy) {
|
||||
balloonVel[0] = vx;
|
||||
balloonVel[1] = vy;
|
||||
}
|
||||
public void setAirTemp(int temperature) {
|
||||
envelopeAirTemp = temperature;
|
||||
}
|
||||
|
||||
public void setScale (int mapScale) {
|
||||
if (mapScale < 2) {
|
||||
scale = 2;
|
||||
} else if (mapScale > 128) {
|
||||
scale = 128;
|
||||
} else {
|
||||
scale = mapScale;
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
public int getScale() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
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 ii, jj;
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
|
||||
// |jpanel_x| = |origin_x| + |scale 0 | * |cos(angle) -sin(angle)| * |world_x|
|
||||
// |jpanel_y| |origin_y| | 0 -scale| |sin(angle) cos(angle)| |world_y|
|
||||
|
||||
worldOriginX = (width/2) - (int)(scale * balloonPos[0]);
|
||||
worldOriginY = (height/2) + (int)(scale * balloonPos[1]);
|
||||
|
||||
// ===============================================================================
|
||||
// Draw Sky
|
||||
// ===============================================================================
|
||||
g2d.setPaint(skyColor);
|
||||
g2d.fillRect(0, 0, width, worldOriginY);
|
||||
|
||||
// ===============================================================================
|
||||
// Draw ground.
|
||||
// ===============================================================================
|
||||
g2d.setPaint(groundColor);
|
||||
g2d.fillRect(0, worldOriginY, width, height);
|
||||
|
||||
// ===============================================================================
|
||||
// Draw Balloon
|
||||
// ===============================================================================
|
||||
|
||||
double r_cone_top = envelope_radius * Math.cos(envelope_theta);
|
||||
double h_cone = r_cone_top / Math.tan(envelope_theta);
|
||||
double h = envelope_radius * Math.sin(envelope_theta) + h_cone;
|
||||
double balloon_diameter = 2.0 * envelope_radius;
|
||||
|
||||
// Draw Dome
|
||||
drawSceneOval(g2d, envelope_color_1, balloonPos[0], balloonPos[1]+h, balloon_diameter*Math.cos(Math.toRadians( 0.0)), balloon_diameter);
|
||||
drawSceneOval(g2d, envelope_color_2, balloonPos[0], balloonPos[1]+h, balloon_diameter*Math.cos(Math.toRadians(22.5)), balloon_diameter);
|
||||
drawSceneOval(g2d, envelope_color_1, balloonPos[0], balloonPos[1]+h, balloon_diameter*Math.cos(Math.toRadians(37.5)), balloon_diameter);
|
||||
drawSceneOval(g2d, envelope_color_2, balloonPos[0], balloonPos[1]+h, balloon_diameter*Math.cos(Math.toRadians(52.5)), balloon_diameter);
|
||||
drawSceneOval(g2d, envelope_color_1, balloonPos[0], balloonPos[1]+h, balloon_diameter*Math.cos(Math.toRadians(67.5)), balloon_diameter);
|
||||
drawSceneOval(g2d, envelope_color_2, balloonPos[0], balloonPos[1]+h, balloon_diameter*Math.cos(Math.toRadians(82.5)), balloon_diameter);
|
||||
drawSceneOval(g2d, envelope_phong, balloonPos[0], balloonPos[1]+h+4.0, balloon_diameter*Math.cos(Math.toRadians( 40.0)), balloon_diameter*Math.cos(Math.toRadians( 60.0)));
|
||||
|
||||
// Draw Cone
|
||||
cone.color = envelope_color_1;
|
||||
double rt = r_cone_top * Math.cos( Math.toRadians( 0.0));
|
||||
cone.x[0] = -rt;
|
||||
cone.y[0] = h_cone;
|
||||
cone.x[1] = rt;
|
||||
cone.y[1] = h_cone;
|
||||
cone.x[2] = 0.0;
|
||||
cone.y[2] = 0.0;
|
||||
cone.x[3] = 0.0;
|
||||
cone.y[3] = 0.0;
|
||||
drawScenePoly(g2d, cone, 0.0, balloonPos[0], balloonPos[1]);
|
||||
|
||||
cone.color = envelope_color_2;
|
||||
rt = r_cone_top * Math.cos( Math.toRadians(22.5));
|
||||
cone.x[0] = -rt;
|
||||
cone.x[1] = rt;
|
||||
drawScenePoly(g2d, cone, 0.0, balloonPos[0], balloonPos[1]);
|
||||
|
||||
cone.color = envelope_color_1;
|
||||
rt = r_cone_top * Math.cos( Math.toRadians(37.5));
|
||||
cone.x[0] = -rt;
|
||||
cone.x[1] = rt;
|
||||
drawScenePoly(g2d, cone, 0.0, balloonPos[0], balloonPos[1]);
|
||||
|
||||
cone.color = envelope_color_2;
|
||||
rt = r_cone_top * Math.cos( Math.toRadians(52.5));
|
||||
cone.x[0] = -rt;
|
||||
cone.x[1] = rt;
|
||||
drawScenePoly(g2d, cone, 0.0, balloonPos[0], balloonPos[1]);
|
||||
|
||||
cone.color = envelope_color_1;
|
||||
rt = r_cone_top * Math.cos( Math.toRadians(67.5));
|
||||
cone.x[0] = -rt;
|
||||
cone.x[1] = rt;
|
||||
drawScenePoly(g2d, cone, 0.0, balloonPos[0], balloonPos[1]);
|
||||
|
||||
cone.color = envelope_color_2;
|
||||
rt = r_cone_top * Math.cos( Math.toRadians(82.5));
|
||||
cone.x[0] = -rt;
|
||||
cone.x[1] = rt;
|
||||
drawScenePoly(g2d, cone, 0.0, balloonPos[0], balloonPos[1]);
|
||||
|
||||
// Draw Upright
|
||||
drawScenePoly(g2d, upright, 0.0, balloonPos[0], balloonPos[1]);
|
||||
|
||||
// Draw Basket
|
||||
drawScenePoly(g2d, basket, 0.0, balloonPos[0], balloonPos[1]);
|
||||
// ===============================================================================
|
||||
// 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;
|
||||
|
||||
int lower = ((int)(( - worldOriginX)/(scale * tickRange)) + 1) * tickRange;
|
||||
int upper = ((int)((width - worldOriginX)/(scale * tickRange)) + 1) * tickRange;
|
||||
|
||||
g2d.setPaint(Color.WHITE);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// ===============================================================================
|
||||
// Draw Information
|
||||
// ===============================================================================
|
||||
g2d.drawString ( String.format("SCALE: %d pixels/meter",scale), 20,20);
|
||||
g2d.drawString ( String.format("Envelope Air-Temp (°C) : [%d]", envelopeAirTemp), 20,40);
|
||||
g2d.drawString ( String.format("Balloon Pos: [%.2f, %.2f]", balloonPos[0], balloonPos[1]), 20,60);
|
||||
g2d.drawString ( String.format("Balloon Vel: [%.2f, %.2f]", balloonVel[0], balloonVel[1]), 20,80);
|
||||
|
||||
}
|
||||
|
||||
@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 TemperatureCtrlPanel extends JPanel implements ActionListener {
|
||||
private RangeView rangeView;
|
||||
private JButton increaseTempButton, decreaseTempButton;
|
||||
|
||||
public TemperatureCtrlPanel(RangeView view) {
|
||||
rangeView = view;
|
||||
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
|
||||
setBorder( BorderFactory.createEtchedBorder(EtchedBorder.RAISED));
|
||||
|
||||
increaseTempButton = new JButton("\u25b2");
|
||||
increaseTempButton.addActionListener(this);
|
||||
increaseTempButton.setActionCommand("increaseTemp");
|
||||
increaseTempButton.setToolTipText("Increase Temperature");
|
||||
|
||||
decreaseTempButton = new JButton("\u25bc");
|
||||
decreaseTempButton.addActionListener(this);
|
||||
decreaseTempButton.setActionCommand("decreaseTemp");
|
||||
decreaseTempButton.setToolTipText("Decrease Temperature");
|
||||
|
||||
add(increaseTempButton);
|
||||
add(decreaseTempButton);
|
||||
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String s = e.getActionCommand();
|
||||
switch (s) {
|
||||
case "increaseTemp":
|
||||
rangeView.incTemperature();
|
||||
break;
|
||||
case "decreaseTemp":
|
||||
rangeView.decTemperature();
|
||||
break;
|
||||
default:
|
||||
System.out.println("Unknown Action Command:" + s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ControlPanel extends JPanel implements ActionListener {
|
||||
|
||||
private RangeView rangeView;
|
||||
private JButton zoomOutButton, zoomInButton;
|
||||
private JButton shutDownButton;
|
||||
private TemperatureCtrlPanel temperatureCtrlPanel;
|
||||
|
||||
public ControlPanel(RangeView view) {
|
||||
|
||||
rangeView = view;
|
||||
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
|
||||
|
||||
JPanel labeledTemperatureCtrlPanel = new JPanel();
|
||||
labeledTemperatureCtrlPanel.setLayout(new BoxLayout(labeledTemperatureCtrlPanel, BoxLayout.Y_AXIS));
|
||||
JLabel temperatureControlLabel = new JLabel("Temperature Control");
|
||||
temperatureControlLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
|
||||
labeledTemperatureCtrlPanel.add(temperatureControlLabel);
|
||||
temperatureCtrlPanel = new TemperatureCtrlPanel(rangeView);
|
||||
labeledTemperatureCtrlPanel.add( temperatureCtrlPanel );
|
||||
add(labeledTemperatureCtrlPanel);
|
||||
|
||||
zoomOutButton = new JButton("Zoom Out");
|
||||
zoomOutButton.addActionListener(this);
|
||||
zoomOutButton.setActionCommand("zoomout");
|
||||
zoomOutButton.setToolTipText("Zoom Out");
|
||||
add(zoomOutButton);
|
||||
|
||||
zoomInButton = new JButton("Zoom In");
|
||||
zoomInButton.addActionListener(this);
|
||||
zoomInButton.setActionCommand("zoomin");
|
||||
zoomInButton.setToolTipText("Zoom In");
|
||||
add(zoomInButton);
|
||||
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String s = e.getActionCommand();
|
||||
switch (s) {
|
||||
case "zoomout":
|
||||
rangeView.setScale( rangeView.getScale() / 2 );
|
||||
break;
|
||||
case "zoomin":
|
||||
rangeView.setScale( rangeView.getScale() * 2 );
|
||||
break;
|
||||
default:
|
||||
System.out.println("Unknown Action Command:" + s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // class ControlPanel
|
||||
|
||||
public class BalloonDisplay extends JFrame {
|
||||
|
||||
private RangeView rangeView;
|
||||
private BufferedReader in;
|
||||
private DataOutputStream out;
|
||||
private JPanel panelGroup0;
|
||||
private JPanel panelGroup1;
|
||||
private ControlPanel controlPanel;
|
||||
|
||||
public BalloonDisplay(RangeView arena) {
|
||||
setTitle("Balloon Range");
|
||||
|
||||
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(8);
|
||||
rangeView.setballoonPos (0.0, 2.0);
|
||||
|
||||
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 BalloonDisplay.jar <port-number>\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;
|
||||
|
||||
// ==========================================================
|
||||
// Handle program arguments.
|
||||
// ==========================================================
|
||||
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 posx = 0.0;
|
||||
double posy = 0.0;
|
||||
double velx = 0.0;
|
||||
double vely = 0.0;
|
||||
int airtemp = 0;
|
||||
|
||||
// Outbound command variables
|
||||
int temperature_change_command;
|
||||
|
||||
int simMode = 0;
|
||||
boolean standalone = false;
|
||||
|
||||
int mapScale = 32 ; // pixels per meter.
|
||||
|
||||
RangeView rangeView = new RangeView( mapScale);
|
||||
BalloonDisplay balloonDisplay = new BalloonDisplay( rangeView);
|
||||
balloonDisplay.setVisible(true);
|
||||
balloonDisplay.drawRangeView();
|
||||
|
||||
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);
|
||||
balloonDisplay.connectToServer(host, port);
|
||||
|
||||
balloonDisplay.out.writeBytes("trick.var_set_client_tag(\"BalloonDisplay\") \n");
|
||||
balloonDisplay.out.flush();
|
||||
|
||||
// Have the Variable Server send us the simulation mode ONCE.
|
||||
balloonDisplay.out.writeBytes( "trick.var_add(\"trick_sys.sched.mode\")\n" +
|
||||
"trick.var_send() \n" +
|
||||
"trick.var_clear() \n");
|
||||
balloonDisplay.out.flush();
|
||||
|
||||
// Read the response and extract the simulation mode.
|
||||
try {
|
||||
String line;
|
||||
String field[];
|
||||
line = balloonDisplay.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:
|
||||
balloonDisplay.out.writeBytes( "trick.var_pause() \n" +
|
||||
"trick.var_add(\"dyn.balloon.pos[0]\")\n" +
|
||||
"trick.var_add(\"dyn.balloon.pos[1]\")\n" +
|
||||
"trick.var_add(\"dyn.balloon.vel[0]\")\n" +
|
||||
"trick.var_add(\"dyn.balloon.vel[1]\")\n" +
|
||||
"trick.var_add(\"dyn.balloon.envelope_air_temperature\")\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" );
|
||||
balloonDisplay.out.flush();
|
||||
|
||||
while (go) {
|
||||
|
||||
// Recieve and parse periodic data response from the variable server.
|
||||
try {
|
||||
String line;
|
||||
String field[];
|
||||
line = balloonDisplay.in.readLine();
|
||||
field = line.split("\t");
|
||||
posx = Double.parseDouble( field[1]);
|
||||
posy = Double.parseDouble( field[2]);
|
||||
velx = Double.parseDouble( field[3]);
|
||||
vely = Double.parseDouble( field[4]);
|
||||
airtemp = Integer.parseInt( field[5]);
|
||||
simMode = Integer.parseInt( field[6]);
|
||||
} catch (IOException | NullPointerException e ) {
|
||||
go = false;
|
||||
}
|
||||
|
||||
// Update the display data.
|
||||
rangeView.setballoonPos(posx, posy);
|
||||
rangeView.setBalloonVel(velx, vely);
|
||||
rangeView.setAirTemp(airtemp);
|
||||
|
||||
temperature_change_command = rangeView.getDeltaTemp();
|
||||
balloonDisplay.out.writeBytes( String.format("dyn.balloon.temperature_change_command = %d ;\n", temperature_change_command ));
|
||||
rangeView.resetDeltaTemp();
|
||||
|
||||
balloonDisplay.out.flush();
|
||||
|
||||
// Update the scene.
|
||||
balloonDisplay.drawRangeView();
|
||||
|
||||
} // while
|
||||
} // main
|
||||
} // class
|
Loading…
Reference in New Issue
Block a user