You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
98 lines
3.0 KiB
98 lines
3.0 KiB
#!/usr/local/bin/python3
|
|
"""Script to generate a fixture of a box falling on a saw."""
|
|
|
|
import argparse
|
|
import json
|
|
import pathlib
|
|
|
|
import numpy
|
|
from shapely.geometry import Polygon
|
|
from shapely.ops import cascaded_union
|
|
|
|
from fixture_utils import *
|
|
|
|
|
|
def generate_fixture(args: argparse.Namespace) -> dict:
|
|
"""Generate a fixture of a N boxes stacked on top of each other."""
|
|
numpy.random.seed(seed=0) # Deterministic random results
|
|
|
|
fixture = generate_custom_fixture(args)
|
|
rigid_bodies = fixture["rigid_body_problem"]["rigid_bodies"]
|
|
|
|
# Dimensions of the table:
|
|
# https://www.dimensions.guide/element/7-foot-billiards-pool-table
|
|
width = 1.98 # m
|
|
height = .99 # m
|
|
thickness = .0019 # m
|
|
rigid_bodies.append(
|
|
generate_walls_body(width / 2, height / 2, numpy.zeros(2), thickness))
|
|
|
|
# Ball settings
|
|
radius = 0.057 / 2 # m
|
|
ball_vertices = generate_regular_ngon_vertices(args.num_points, radius)
|
|
|
|
mass = 0.170 # Kg
|
|
area = compute_regular_ngon_area(ball_vertices) # m²
|
|
density = mass / area # Kg / m²
|
|
|
|
ball = {
|
|
"vertices": ball_vertices.tolist(),
|
|
"polygons": [ball_vertices.tolist()],
|
|
"edges": generate_ngon_edges(args.num_points).tolist(),
|
|
"oriented": True,
|
|
"velocity": [0.0, 0.0, 0.0],
|
|
"is_dof_fixed": [False, False, False],
|
|
"masses": numpy.full(args.num_points, mass / args.num_points).tolist(),
|
|
"density": density
|
|
}
|
|
|
|
# Add the triangle of balls
|
|
x = width / 4
|
|
for row in range(5):
|
|
y = -1.15 * radius * row
|
|
for i in range(row + 1):
|
|
ball["position"] = [x, y]
|
|
ball["theta"] = numpy.random.random() * (360 / args.num_points)
|
|
rigid_bodies.append(ball.copy())
|
|
y += 2.3 * radius
|
|
x += 2 * radius
|
|
|
|
# Add the cue ball
|
|
ball["position"] = [-width / 4, 0]
|
|
ball["theta"] = 0
|
|
# Typical Pool Ball Speeds: Powerful Break
|
|
# https://billiards.colostate.edu/faq/speed/typical/
|
|
break_speed = 10.729 # m / s
|
|
ball["velocity"] = [break_speed, 0.0, 0.0]
|
|
rigid_bodies.append(ball.copy())
|
|
|
|
return fixture
|
|
|
|
|
|
def main():
|
|
"""Parse command-line arguments to generate the desired fixture."""
|
|
parser = create_argument_parser("generate a billiards fixture",
|
|
default_timestep=1e-3,
|
|
default_initial_epsilon=1e-2,
|
|
default_restitution_coefficient=1)
|
|
parser.add_argument(
|
|
"--num-points",
|
|
type=int,
|
|
default=8,
|
|
help="number of points/edges used to discritize the balls")
|
|
args = parser.parse_args()
|
|
|
|
if args.out_path is None:
|
|
directory = pathlib.Path(__file__).resolve().parents[1] / "fixtures"
|
|
args.out_path = directory / "billiards.json"
|
|
args.out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
print_args(args)
|
|
|
|
fixture = generate_fixture(args)
|
|
|
|
save_fixture(fixture, args.out_path)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
|