mirror of
https://github.com/nasa/trick.git
synced 2024-12-18 20:57:55 +00:00
Add progress on SIM_pool
This commit is contained in:
parent
ade5932e87
commit
b869f851f5
10
trick_sims/SIM_pool/Modified_data/realtime.py
Normal file
10
trick_sims/SIM_pool/Modified_data/realtime.py
Normal 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)
|
30
trick_sims/SIM_pool/RUN_test/input.py
Normal file
30
trick_sims/SIM_pool/RUN_test/input.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
|
||||||
|
exec(open("./Modified_data/realtime.py").read())
|
||||||
|
|
||||||
|
dyn.table.numBalls = 2
|
||||||
|
dyn.table.balls = trick.TMM_declare_var_1d("Ball*", dyn.table.numBalls)
|
||||||
|
|
||||||
|
id1 = dyn.table.addBall(-2, .5, 1, 1, False);
|
||||||
|
id2 = dyn.table.addBall(1, .5, 1, 1, False);
|
||||||
|
|
||||||
|
dyn.table.setBallVel(id1, 0.5, 0);
|
||||||
|
|
||||||
|
dyn_integloop.getIntegrator(trick.Euler, 6*dyn.table.numBalls)
|
||||||
|
|
||||||
|
#==========================================
|
||||||
|
# Start the Graphics Client
|
||||||
|
#==========================================
|
||||||
|
varServerPort = trick.var_server_get_port();
|
||||||
|
PoolTableDisplay_path = "models/graphics/dist/PoolTableDisplay.jar"
|
||||||
|
|
||||||
|
if (os.path.isfile(PoolTableDisplay_path)) :
|
||||||
|
PoolTableDisplay_cmd = "java -jar " \
|
||||||
|
+ PoolTableDisplay_path \
|
||||||
|
+ " " + str(varServerPort) + " &" ;
|
||||||
|
print(PoolTableDisplay_cmd)
|
||||||
|
os.system( PoolTableDisplay_cmd);
|
||||||
|
else :
|
||||||
|
print('============================================================================================')
|
||||||
|
print('PoolTableDisplay needs to be built. Please \"cd\" into ../models/graphics and type \"make\".')
|
||||||
|
print('============================================================================================')
|
24
trick_sims/SIM_pool/S_define
Normal file
24
trick_sims/SIM_pool/S_define
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/************************************************************
|
||||||
|
PURPOSE:
|
||||||
|
( Simulation of Pool Table. )
|
||||||
|
LIBRARY DEPENDENCIES:
|
||||||
|
((pool_table/src/pool_table.cpp))
|
||||||
|
*************************************************************/
|
||||||
|
#include "sim_objects/default_trick_sys.sm"
|
||||||
|
##include "pool_table/include/pool_table.hh"
|
||||||
|
|
||||||
|
class PoolTableSimObject : public Trick::SimObject {
|
||||||
|
public:
|
||||||
|
PoolTable table;
|
||||||
|
|
||||||
|
PoolTableSimObject() {
|
||||||
|
("default_data") table.default_data() ;
|
||||||
|
("initialization") table.state_init() ;
|
||||||
|
("derivative") table.state_deriv() ;
|
||||||
|
("integration") trick_ret = table.state_integ() ;
|
||||||
|
("dynamic_event") table.collision() ;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PoolTableSimObject dyn;
|
||||||
|
IntegLoop dyn_integloop(0.1) dyn;
|
2
trick_sims/SIM_pool/S_overrides.mk
Normal file
2
trick_sims/SIM_pool/S_overrides.mk
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
TRICK_CFLAGS += -Imodels -I/usr/local/include/eigen3/
|
||||||
|
TRICK_CXXFLAGS += -Imodels -I/usr/local/include/eigen3/
|
333
trick_sims/SIM_pool/models/graphics/src/PoolTableDisplay.java
Normal file
333
trick_sims/SIM_pool/models/graphics/src/PoolTableDisplay.java
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
/*
|
||||||
|
* Trick
|
||||||
|
* 2020 (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 javax.swing.BoxLayout;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Ball {
|
||||||
|
static int numColors = 9;
|
||||||
|
static Color[] colorList = {
|
||||||
|
Color.WHITE,
|
||||||
|
Color.YELLOW,
|
||||||
|
Color.BLUE,
|
||||||
|
Color.RED,
|
||||||
|
Color.MAGENTA,
|
||||||
|
Color.GREEN,
|
||||||
|
Color.MAGENTA,
|
||||||
|
Color.BLACK
|
||||||
|
};
|
||||||
|
|
||||||
|
public Color color;
|
||||||
|
public double x;
|
||||||
|
public double y;
|
||||||
|
public double radius;
|
||||||
|
public int identity;
|
||||||
|
public Ball (int id) {
|
||||||
|
identity = id;
|
||||||
|
x = 0.0;
|
||||||
|
y = 0.0;
|
||||||
|
radius = 0.5;
|
||||||
|
color = colorList[id % numColors];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ControlPanel extends JPanel implements ActionListener {
|
||||||
|
|
||||||
|
private RangeView rangeView;
|
||||||
|
private JButton zoomOutButton, zoomInButton;
|
||||||
|
|
||||||
|
public ControlPanel(RangeView view) {
|
||||||
|
|
||||||
|
rangeView = view;
|
||||||
|
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
class RangeView extends JPanel {
|
||||||
|
|
||||||
|
private int scale;
|
||||||
|
private Color backGroundColor;
|
||||||
|
|
||||||
|
// Origin of world coordinates in jpanel coordinates.
|
||||||
|
private int worldOriginX;
|
||||||
|
private int worldOriginY;
|
||||||
|
|
||||||
|
public Ball[] balls;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class constructor.
|
||||||
|
*/
|
||||||
|
public RangeView( int mapScale, int numberOfBalls) {
|
||||||
|
setScale(mapScale);
|
||||||
|
backGroundColor = new Color(0.2f, 0.6f, 0.2f);
|
||||||
|
balls = new Ball[numberOfBalls];
|
||||||
|
for (int ii=0 ; ii<numberOfBalls ; ii++) {
|
||||||
|
balls[ii] = new Ball(ii);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScale (int mapScale) {
|
||||||
|
if (mapScale < 4) {
|
||||||
|
scale = 4;
|
||||||
|
} else if (mapScale > 128) {
|
||||||
|
scale = 128;
|
||||||
|
} else {
|
||||||
|
scale = mapScale;
|
||||||
|
}
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getScale() {
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawCenteredCircle(Graphics2D g, int x, int y, int d) {
|
||||||
|
x = x-(d/2);
|
||||||
|
y = y-(d/2);
|
||||||
|
g.fillOval(x,y,d,d);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
worldOriginY = (height/2);
|
||||||
|
|
||||||
|
// Draw Background
|
||||||
|
g2d.setPaint(backGroundColor);
|
||||||
|
g2d.fillRect(0, 0, width, height);
|
||||||
|
|
||||||
|
// Draw balls
|
||||||
|
for (int ii = 0; ii < balls.length ; ii++) {
|
||||||
|
g2d.setPaint(balls[ii].color);
|
||||||
|
int bx = (int)(worldOriginX + scale * balls[ii].x);
|
||||||
|
int by = (int)(worldOriginY - scale * balls[ii].y);
|
||||||
|
drawCenteredCircle(g2d, bx, by, (int)(scale * 2 * balls[ii].radius));
|
||||||
|
g2d.setPaint(Color.BLACK);
|
||||||
|
g2d.drawString ( String.format("%d",ii), bx,by);
|
||||||
|
}
|
||||||
|
|
||||||
|
g2d.drawString ( String.format("SCALE: %d pixels/meter",scale), 20,20);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paintComponent(Graphics g) {
|
||||||
|
super.paintComponent(g);
|
||||||
|
doDrawing(g);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PoolTableDisplay extends JFrame {
|
||||||
|
|
||||||
|
private RangeView rangeView;
|
||||||
|
private BufferedReader in;
|
||||||
|
private DataOutputStream out;
|
||||||
|
|
||||||
|
public PoolTableDisplay() {
|
||||||
|
|
||||||
|
rangeView = null;
|
||||||
|
setTitle("Ball Arena");
|
||||||
|
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 createGUI( int mapScale, int numberOfBalls ) {
|
||||||
|
|
||||||
|
rangeView = new RangeView(mapScale, numberOfBalls);
|
||||||
|
JPanel panel1 = new JPanel();
|
||||||
|
panel1.setLayout(new BoxLayout(panel1, BoxLayout.X_AXIS));
|
||||||
|
panel1.add(rangeView);
|
||||||
|
|
||||||
|
ControlPanel controlPanel = new ControlPanel(rangeView);
|
||||||
|
JPanel panel0 = new JPanel();
|
||||||
|
panel0.setLayout(new BoxLayout(panel0, BoxLayout.Y_AXIS));
|
||||||
|
panel0.add(panel1);
|
||||||
|
panel0.add(controlPanel);
|
||||||
|
add(panel0);
|
||||||
|
setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void printHelpText() {
|
||||||
|
System.out.println(
|
||||||
|
"----------------------------------------------------------------------\n"
|
||||||
|
+ "usage: java jar PoolTableDisplay.jar <port-number>\n"
|
||||||
|
+ "----------------------------------------------------------------------\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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).
|
||||||
|
int mapScale = 32 ; // pixels per meter.
|
||||||
|
int nballs = 7;
|
||||||
|
|
||||||
|
if (port == 0) {
|
||||||
|
System.out.println("No variable server port specified.");
|
||||||
|
printHelpText();
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
PoolTableDisplay poolTableDisplay = new PoolTableDisplay();
|
||||||
|
|
||||||
|
// Connect to the Trick simulation's variable server.
|
||||||
|
System.out.println("Connecting to: " + host + ":" + port);
|
||||||
|
poolTableDisplay.connectToServer(host, port);
|
||||||
|
poolTableDisplay.out.writeBytes("trick.var_set_client_tag(\"PoolTableDisplay\") \n");
|
||||||
|
poolTableDisplay.out.flush();
|
||||||
|
|
||||||
|
// Get the number of balls.
|
||||||
|
poolTableDisplay.out.writeBytes(
|
||||||
|
"trick.var_add(\"dyn.table.numBalls\")\n" +
|
||||||
|
"trick.var_send() \n" +
|
||||||
|
"trick.var_clear() \n");
|
||||||
|
poolTableDisplay.out.flush();
|
||||||
|
try {
|
||||||
|
String line;
|
||||||
|
String field[];
|
||||||
|
line = poolTableDisplay.in.readLine();
|
||||||
|
field = line.split("\t");
|
||||||
|
nballs = Integer.parseInt( field[1]);
|
||||||
|
} catch (IOException | NullPointerException e ) {
|
||||||
|
go = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
poolTableDisplay.createGUI(mapScale, nballs);
|
||||||
|
|
||||||
|
// Get the Radii of the balls.
|
||||||
|
for ( ii = 0; ii < nballs; ii ++) {
|
||||||
|
poolTableDisplay.out.writeBytes( String.format("trick.var_add(\"dyn.table.balls[%d][0].radius\")\n", ii));
|
||||||
|
}
|
||||||
|
poolTableDisplay.out.flush();
|
||||||
|
poolTableDisplay.out.writeBytes(
|
||||||
|
"trick.var_send() \n" +
|
||||||
|
"trick.var_clear() \n");
|
||||||
|
poolTableDisplay.out.flush();
|
||||||
|
try {
|
||||||
|
String line;
|
||||||
|
String field[];
|
||||||
|
line = poolTableDisplay.in.readLine();
|
||||||
|
field = line.split("\t");
|
||||||
|
for ( ii=0; ii < nballs; ii++) {
|
||||||
|
// poolTableDisplay.rangeView.balls[ii].radius = Double.parseDouble( field[ii+1]);
|
||||||
|
}
|
||||||
|
} catch (IOException | NullPointerException e ) {
|
||||||
|
go = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the Positions of the balls, and update the display, periodically.
|
||||||
|
poolTableDisplay.out.writeBytes( "trick.var_pause() \n");
|
||||||
|
for ( ii = 0; ii < nballs; ii ++) {
|
||||||
|
poolTableDisplay.out.writeBytes(
|
||||||
|
String.format("trick.var_add(\"dyn.table.balls[%d][0].pos[0]\")\n", ii)
|
||||||
|
+ String.format("trick.var_add(\"dyn.table.balls[%d][0].pos[1]\")\n", ii)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
poolTableDisplay.out.writeBytes("trick.var_ascii() \n" +
|
||||||
|
String.format("trick.var_cycle(%.3f)\n", dt) +
|
||||||
|
"trick.var_unpause() \n" );
|
||||||
|
poolTableDisplay.out.flush();
|
||||||
|
while (go) {
|
||||||
|
try {
|
||||||
|
String line;
|
||||||
|
String field[];
|
||||||
|
line = poolTableDisplay.in.readLine();
|
||||||
|
// System.out.println("Sim->Client:" + line);
|
||||||
|
field = line.split("\t");
|
||||||
|
for ( ii=0; ii < nballs; ii++) {
|
||||||
|
poolTableDisplay.rangeView.balls[ii].x = Double.parseDouble( field[2*ii+1]);
|
||||||
|
poolTableDisplay.rangeView.balls[ii].y = Double.parseDouble( field[2*ii+2]);
|
||||||
|
}
|
||||||
|
} catch (IOException | NullPointerException e ) {
|
||||||
|
go = false;
|
||||||
|
}
|
||||||
|
// Update the scene.
|
||||||
|
poolTableDisplay.rangeView.repaint();
|
||||||
|
} // while
|
||||||
|
} // main
|
||||||
|
} // class
|
46
trick_sims/SIM_pool/models/pool_table/include/ball.hh
Normal file
46
trick_sims/SIM_pool/models/pool_table/include/ball.hh
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/********************************* TRICK HEADER *******************************
|
||||||
|
PURPOSE: ( Simulate pool balls. )
|
||||||
|
LIBRARY DEPENDENCY:
|
||||||
|
((ball.o))
|
||||||
|
*******************************************************************************/
|
||||||
|
#ifndef _ball_hh_
|
||||||
|
#define _ball_hh_
|
||||||
|
|
||||||
|
// #include <Eigen/Core>
|
||||||
|
|
||||||
|
// monotonically increasing ID
|
||||||
|
static int id = 0;
|
||||||
|
|
||||||
|
class Ball {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Ball(double x, double y, double mass, double radius, bool isFixed, int id);
|
||||||
|
Ball () {}
|
||||||
|
|
||||||
|
// Z component should always be 0, unless someone tries to add jumps in the future
|
||||||
|
double pos[3];
|
||||||
|
double prevPos[3];
|
||||||
|
double vel[3];
|
||||||
|
// Used to store derivatives between deriv and integration steps
|
||||||
|
double accel[3];
|
||||||
|
|
||||||
|
// Relating to angular velocity
|
||||||
|
double relativeVel[3];
|
||||||
|
double w[3];
|
||||||
|
double angular_accel[3];
|
||||||
|
|
||||||
|
double color[3];
|
||||||
|
|
||||||
|
double mass;
|
||||||
|
double radius;
|
||||||
|
bool fixed;
|
||||||
|
bool isCue;
|
||||||
|
int sliding;
|
||||||
|
|
||||||
|
unsigned int id;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ball* CreateBall(double x, double y, double mass, double radius, bool isFixed);
|
||||||
|
|
||||||
|
#endif
|
46
trick_sims/SIM_pool/models/pool_table/include/bumper.hh
Normal file
46
trick_sims/SIM_pool/models/pool_table/include/bumper.hh
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/********************************* TRICK HEADER *******************************
|
||||||
|
PURPOSE: ( Pool bumper class. )
|
||||||
|
LIBRARY DEPENDENCY:
|
||||||
|
((bumper.o))
|
||||||
|
*******************************************************************************/
|
||||||
|
#ifndef _bumper_hh_
|
||||||
|
#define _bumper_hh_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// this should definitely go somewhere else
|
||||||
|
// maybe make a geometry libary
|
||||||
|
class Point {
|
||||||
|
public:
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
|
||||||
|
Point(double x, double y) : x(x), y(y) {}
|
||||||
|
Point() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Line {
|
||||||
|
public:
|
||||||
|
Point p1;
|
||||||
|
Point p2;
|
||||||
|
|
||||||
|
Line (Point p1, Point p2) : p1(p1), p2(p2) {}
|
||||||
|
Line () {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Bumper {
|
||||||
|
public:
|
||||||
|
void AddPointToRender(double x, double y);
|
||||||
|
void AddBorder (double x1, double y1, double x2, double y2);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Actual line that can be collided with
|
||||||
|
Line border;
|
||||||
|
|
||||||
|
// Shape that should be rendered
|
||||||
|
// Size should be dynamic
|
||||||
|
std::vector<Point *> renderedShape;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
58
trick_sims/SIM_pool/models/pool_table/include/pool_table.hh
Normal file
58
trick_sims/SIM_pool/models/pool_table/include/pool_table.hh
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/************************************************************************
|
||||||
|
PURPOSE: (Simulate a pool table.)
|
||||||
|
LIBRARY DEPENDENCIES:
|
||||||
|
((pool_table/src/pool_table.o))
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _POOL_TABLE_H_
|
||||||
|
#define _POOL_TABLE_H_
|
||||||
|
#include "trick/regula_falsi.h"
|
||||||
|
#include "ball.hh"
|
||||||
|
#include "bumper.hh"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
class PoolTable {
|
||||||
|
|
||||||
|
public:
|
||||||
|
PoolTable () : numBalls(0), numAssociations(0) {}
|
||||||
|
|
||||||
|
int addBall (double x, double y, double mass, double radius, bool fixed);
|
||||||
|
int addBumper (double x1, double y1, double x2, double y2);
|
||||||
|
|
||||||
|
int setBallPos(int id, double x, double y);
|
||||||
|
int setBallVel(int id, double v_x, double v_y);
|
||||||
|
|
||||||
|
// Ball ** balls;
|
||||||
|
// Bumper ** bumpers;
|
||||||
|
Ball** balls;
|
||||||
|
Bumper** bumpers;
|
||||||
|
|
||||||
|
// Ball-ball collisions
|
||||||
|
int nextBallSlot = 0;
|
||||||
|
unsigned int numBalls;
|
||||||
|
unsigned int numAssociations;
|
||||||
|
REGULA_FALSI* ballAssociations;
|
||||||
|
|
||||||
|
// Ball-bumper collisions
|
||||||
|
unsigned int numBumpers;
|
||||||
|
unsigned int numCombos;
|
||||||
|
REGULA_FALSI* bumperAssociations;
|
||||||
|
|
||||||
|
//void ballCollision(Ball &b1, Ball &b2);
|
||||||
|
|
||||||
|
int default_data();
|
||||||
|
int state_init();
|
||||||
|
int state_deriv();
|
||||||
|
int state_integ();
|
||||||
|
double collision();
|
||||||
|
|
||||||
|
// Sim constants that should be user-controllable
|
||||||
|
double frictionRolling = 0.05;
|
||||||
|
double frictionSliding = 0.25;
|
||||||
|
double frictionScale = 1;
|
||||||
|
double frictionTolerance = 0.0005;
|
||||||
|
double coefficientOfElasticity = 0.99;
|
||||||
|
|
||||||
|
};
|
||||||
|
#endif
|
35
trick_sims/SIM_pool/models/pool_table/src/ball.cpp
Normal file
35
trick_sims/SIM_pool/models/pool_table/src/ball.cpp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/********************************* TRICK HEADER *******************************
|
||||||
|
PURPOSE: ( Simulate balls contacting boundaries. )
|
||||||
|
LIBRARY DEPENDENCY:
|
||||||
|
((ball.o))
|
||||||
|
*******************************************************************************/
|
||||||
|
#include "../include/ball.hh"
|
||||||
|
// #include "trick/memorymanager_c_intf.h"
|
||||||
|
|
||||||
|
#include "trick/MemoryManager.hh"
|
||||||
|
extern Trick::MemoryManager* trick_MM;
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
Ball::Ball(double x, double y, double mass, double radius, bool isFixed, int id) :
|
||||||
|
mass(mass),
|
||||||
|
fixed(isFixed),
|
||||||
|
id(id)
|
||||||
|
{
|
||||||
|
pos[0] = x;
|
||||||
|
pos[1] = y;
|
||||||
|
pos[2] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ball* CreateBall(double x, double y, double mass, double radius, bool isFixed) {
|
||||||
|
// // Ball* b = (Ball*)TMM_declare_var_s("Ball");
|
||||||
|
// Ball *b = new Ball(x, y, mass, radius, isFixed, 0);
|
||||||
|
// trick_MM->declare_extern_var ( b, "Ball");
|
||||||
|
// // Ball *b = (Ball*)trick_MM->declare_var("Ball");
|
||||||
|
|
||||||
|
// // return (new (b) Ball(x, y, mass, radius, isFixed, 0));
|
||||||
|
// return b;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
9
trick_sims/SIM_pool/models/pool_table/src/bumper.cpp
Normal file
9
trick_sims/SIM_pool/models/pool_table/src/bumper.cpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#include "bumper.hh"
|
||||||
|
|
||||||
|
void Bumper::AddPointToRender(double x, double y) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bumper::AddBorder (double x1, double y1, double x2, double y2) {
|
||||||
|
|
||||||
|
}
|
284
trick_sims/SIM_pool/models/pool_table/src/pool_table.cpp
Normal file
284
trick_sims/SIM_pool/models/pool_table/src/pool_table.cpp
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
/********************************* TRICK HEADER *******************************
|
||||||
|
PURPOSE: (Simulate a pool table.)
|
||||||
|
LIBRARY DEPENDENCY:
|
||||||
|
((pool_table.o)
|
||||||
|
(ball.o))
|
||||||
|
*******************************************************************************/
|
||||||
|
#include <math.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include "trick/integrator_c_intf.h"
|
||||||
|
#include "trick/memorymanager_c_intf.h"
|
||||||
|
#include "../include/pool_table.hh"
|
||||||
|
#include "trick/trick_math_proto.h"
|
||||||
|
|
||||||
|
double dot( /* Return: Scalar dot or inner product */
|
||||||
|
double vec1[], /* In: Vector 1 */
|
||||||
|
double vec2[], /* In: Vector 2 */
|
||||||
|
int dim)
|
||||||
|
{
|
||||||
|
double dot = 0;
|
||||||
|
for (int i = 0; i < dim; i++) {
|
||||||
|
dot += vec1[i] * vec2[i];
|
||||||
|
}
|
||||||
|
return dot;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scaleInPlace (double vec[], double scale, int dim) {
|
||||||
|
for (int i = 0; i < dim; i++) {
|
||||||
|
vec[i] *= scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int PoolTable::default_data() {
|
||||||
|
// balls.clear();
|
||||||
|
// bumpers.clear();
|
||||||
|
|
||||||
|
|
||||||
|
// Dev Testing only - should be deleted
|
||||||
|
// int id1 = addBall(0.5, 0.5, 1, 1, false);
|
||||||
|
// int id2 = addBall(0.75, 0.5, 1, 1, false);
|
||||||
|
|
||||||
|
// setBallVel(id1, 0.1, 0);
|
||||||
|
///////////////////////////////////////////
|
||||||
|
|
||||||
|
numBalls = 0;
|
||||||
|
numBumpers = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input stage runs before this, which populates balls and bumpers
|
||||||
|
int PoolTable::state_init() {
|
||||||
|
|
||||||
|
// Do regula falsi setup here
|
||||||
|
|
||||||
|
// Vars for ball/ball collisions
|
||||||
|
double now ;
|
||||||
|
numAssociations = (numBalls*(numBalls-1))/2;
|
||||||
|
ballAssociations = (REGULA_FALSI*)TMM_declare_var_1d("REGULA_FALSI", numAssociations);
|
||||||
|
unsigned int ii,jj;
|
||||||
|
for (ii=1; ii<numBalls; ii++) {
|
||||||
|
for (jj=0; jj<ii; jj++) {
|
||||||
|
unsigned int association_index = ii*(ii-1)/2+jj;
|
||||||
|
ballAssociations[association_index].mode = Decreasing;
|
||||||
|
ballAssociations[association_index].error_tol = 0.0000001;
|
||||||
|
now = get_integ_time() ;
|
||||||
|
reset_regula_falsi( now, &ballAssociations[association_index] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to do the same thing with rail/ball associations
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PoolTable::state_deriv() {
|
||||||
|
// derivative - determine the acceleration here
|
||||||
|
// This is probably just friction
|
||||||
|
// And angular stuff
|
||||||
|
// F = MA => A = M^-1 * F
|
||||||
|
|
||||||
|
// Will have to account for rolling vs sliding here
|
||||||
|
// For now, just rolling
|
||||||
|
|
||||||
|
for (int i = 0; i < numBalls; i++) {
|
||||||
|
// Frictional force a constant applied in the opposing direction of velocity.
|
||||||
|
// Magnitude of velocity is irrelevant
|
||||||
|
|
||||||
|
// std::cout << "ActuaVelocity: " << balls[i]->vel[0] << " " << balls[i]->vel[1] << std::endl;
|
||||||
|
// std::cout << "Velocity Norm: " << velocityNorm[0] << " " << velocityNorm[1] << std::endl;
|
||||||
|
|
||||||
|
// balls[i]->accel[0] = 0;
|
||||||
|
// balls[i]->accel[1] = 0;
|
||||||
|
|
||||||
|
// Has weird behavior when velocity is very small, so only apply friction if velocity is greater than a tolerance
|
||||||
|
if (abs(dv_mag(balls[i]->vel)) > frictionTolerance) {
|
||||||
|
double velocityNorm[3];
|
||||||
|
dv_norm(velocityNorm, balls[i]->vel);
|
||||||
|
|
||||||
|
balls[i]->accel[0] = - (frictionScale * frictionRolling * velocityNorm[0]);
|
||||||
|
balls[i]->accel[1] = - (frictionScale * frictionRolling * velocityNorm[1]);
|
||||||
|
balls[i]->accel[2] = 0;
|
||||||
|
} else {
|
||||||
|
balls[i]->vel[0] = 0;
|
||||||
|
balls[i]->vel[1] = 0;
|
||||||
|
balls[i]->vel[2] = 0;
|
||||||
|
|
||||||
|
balls[i]->accel[0] = 0;
|
||||||
|
balls[i]->accel[1] = 0;
|
||||||
|
balls[i]->accel[2] = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PoolTable::state_integ() {
|
||||||
|
// Apply the acceleration by changing the velocity by the appropriate amount over the time step
|
||||||
|
|
||||||
|
// How many state variables are needed for each ball
|
||||||
|
int n = 6;
|
||||||
|
|
||||||
|
for (int i = 0; i < numBalls; i++) {
|
||||||
|
// State - Need to load 4 values for each ball, but will have to have more when we add angular stuff
|
||||||
|
// pos[0] pos[1] vel[0] vel[1]
|
||||||
|
int inner_index = 0;
|
||||||
|
load_indexed_state(n*i + inner_index++, balls[i]->pos[0]);
|
||||||
|
load_indexed_state(n*i + inner_index++, balls[i]->pos[1]);
|
||||||
|
load_indexed_state(n*i + inner_index++, balls[i]->pos[2]);
|
||||||
|
|
||||||
|
load_indexed_state(n*i + inner_index++, balls[i]->vel[0]);
|
||||||
|
load_indexed_state(n*i + inner_index++, balls[i]->vel[1]);
|
||||||
|
load_indexed_state(n*i + inner_index++, balls[i]->vel[2]);
|
||||||
|
|
||||||
|
// Derivatives of all of this junk
|
||||||
|
// vel[0] vel[1] accel[0] accel[1]
|
||||||
|
|
||||||
|
inner_index = 0;
|
||||||
|
load_indexed_deriv(n*i + inner_index++, balls[i]->vel[0]);
|
||||||
|
load_indexed_deriv(n*i + inner_index++, balls[i]->vel[1]);
|
||||||
|
load_indexed_deriv(n*i + inner_index++, balls[i]->vel[2]);
|
||||||
|
|
||||||
|
load_indexed_deriv(n*i + inner_index++, balls[i]->accel[0]); // Needs to be accel[0]
|
||||||
|
load_indexed_deriv(n*i + inner_index++, balls[i]->accel[1]); // Needs to be accel[1]
|
||||||
|
load_indexed_deriv(n*i + inner_index++, balls[i]->accel[2]); // Needs to be accel[2]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int integration_step = integrate();
|
||||||
|
|
||||||
|
for (int i = 0; i < numBalls; i++) {
|
||||||
|
// pos[0] pos[1] vel[0] vel[1]
|
||||||
|
int inner_index = 0;
|
||||||
|
balls[i]->pos[0] = unload_indexed_state(n*i + inner_index++);
|
||||||
|
balls[i]->pos[1] = unload_indexed_state(n*i + inner_index++);
|
||||||
|
balls[i]->pos[2] = unload_indexed_state(n*i + inner_index++);
|
||||||
|
|
||||||
|
balls[i]->vel[0] = unload_indexed_state(n*i + inner_index++);
|
||||||
|
balls[i]->vel[1] = unload_indexed_state(n*i + inner_index++);
|
||||||
|
balls[i]->vel[2] = unload_indexed_state(n*i + inner_index++);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maybe need a separate scheduled job to handle pockets?
|
||||||
|
// And the cue?
|
||||||
|
// Maybe see if there's some "callback" that can handle user input
|
||||||
|
// There must be, since other sims have control panels too
|
||||||
|
|
||||||
|
double PoolTable::collision() {
|
||||||
|
// Handle when the balls collide with others or with a bumper
|
||||||
|
|
||||||
|
double now ; /* current integration time. */
|
||||||
|
unsigned int first, second;
|
||||||
|
|
||||||
|
unsigned int association_index;
|
||||||
|
double event_tgo;
|
||||||
|
unsigned int ii,jj;
|
||||||
|
|
||||||
|
now = get_integ_time() ;
|
||||||
|
event_tgo = BIG_TGO;
|
||||||
|
|
||||||
|
std::vector<unsigned int> collisionsToProcess;
|
||||||
|
|
||||||
|
for (ii=1; ii<numBalls; ii++) {
|
||||||
|
for (jj=0; jj<ii; jj++) {
|
||||||
|
double diff[3];
|
||||||
|
dv_sub(diff, balls[ii]->pos, balls[jj]->pos);
|
||||||
|
double distanceBetweenBalls = dv_mag(diff);
|
||||||
|
unsigned int associationIndex = ii*(ii-1)/2+jj;
|
||||||
|
|
||||||
|
// boundary is distance between balls - radiuses of balls
|
||||||
|
ballAssociations[associationIndex].error = distanceBetweenBalls - (balls[ii]->radius + balls[jj]->radius);
|
||||||
|
double this_tgo = regula_falsi( now, &(ballAssociations[associationIndex])) ;
|
||||||
|
|
||||||
|
if (this_tgo < event_tgo) {
|
||||||
|
event_tgo = this_tgo;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this_tgo == 0) {
|
||||||
|
// Add this collision to a list of collisions to process
|
||||||
|
collisionsToProcess.push_back(ii);
|
||||||
|
collisionsToProcess.push_back(jj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle collisions
|
||||||
|
for (int i = 0; i < collisionsToProcess.size(); i+=2) {
|
||||||
|
int index1 = collisionsToProcess[i];
|
||||||
|
int index2 = collisionsToProcess[i+1];
|
||||||
|
|
||||||
|
double *q1 = balls[index1]->pos;
|
||||||
|
double *q2 = balls[index2]->pos;
|
||||||
|
|
||||||
|
|
||||||
|
// dg = (q1 - q2) / (|q1 - q2|)
|
||||||
|
double diff[3];
|
||||||
|
dv_sub(diff, q1, q2);
|
||||||
|
double dg[3];
|
||||||
|
dv_norm(dg, diff);
|
||||||
|
|
||||||
|
// Have to stuff both velocities and dg values into 4d vector to do the calculation
|
||||||
|
// Otherwise I have to do more math
|
||||||
|
double dg4[4] = {dg[0], dg[1], -dg[0], -dg[1]};
|
||||||
|
double vel4[4] = {balls[index1]->vel[0], balls[index1]->vel[1], balls[index2]->vel[0], balls[index2]->vel[1]};
|
||||||
|
|
||||||
|
// Calculate the impulse
|
||||||
|
// J = ((-(1 + c) * dg * v) / (dg * M^-1 * dg^T) ) dg
|
||||||
|
// For now let's just pretend all the masses are 1
|
||||||
|
double impulse = ((1.0 + coefficientOfElasticity) * dot(dg4, vel4, 4)) / (dot(dg4, dg4, 4));
|
||||||
|
scaleInPlace(dg, impulse, 4);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return event_tgo;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a ball to the table and return the ID
|
||||||
|
int PoolTable::addBall (double x, double y, double mass, double radius, bool fixed) {
|
||||||
|
int id = nextBallSlot++;
|
||||||
|
if (id < numBalls) {
|
||||||
|
Ball * ball = (Ball*) TMM_declare_var_s("Ball");
|
||||||
|
balls[id] = (new (ball) Ball(x,y,mass,radius, fixed, id));
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a bumper to the table and return the ID
|
||||||
|
// Only takes in the actual effective line, need to add something else for the rendered shape
|
||||||
|
int PoolTable::addBumper (double x1, double y1, double x2, double y2) {
|
||||||
|
// bumpers.push_back(bumper);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PoolTable::setBallPos(int id, double x, double y) {
|
||||||
|
if (id < numBalls && balls[id] != NULL) {
|
||||||
|
balls[id]->pos[0] = x;
|
||||||
|
balls[id]->pos[1] = y;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PoolTable::setBallVel(int id, double v_x, double v_y) {
|
||||||
|
if (id < numBalls && balls[id] != NULL) {
|
||||||
|
balls[id]->vel[0] = v_x;
|
||||||
|
balls[id]->vel[1] = v_y;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user