package gl8080.physics; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import gl8080.physics.domain.ActingForce; import gl8080.physics.domain.PhysicalLaw; import gl8080.physics.domain.Time; import gl8080.physics.domain.World; import gl8080.physics.domain.force.CentripetalForce; import gl8080.physics.domain.force.DummyForce; import gl8080.physics.domain.force.EarthGravity; import gl8080.physics.domain.force.Tension; import gl8080.physics.domain.force.UniversalGravitation; import gl8080.physics.domain.law.LawOfMotion; import gl8080.physics.domain.physical.Ball; import gl8080.physics.domain.primitive.Mass; import gl8080.physics.domain.primitive.Point; import gl8080.physics.domain.primitive.Velocity; import gl8080.physics.view.Axis; import gl8080.physics.view.Camera; import gl8080.physics.view.Space; import gl8080.physics.view.ViewPoint; import gl8080.physics.view.shape.BallLocus; import gl8080.physics.view.shape.BallShape; import javafx.application.Application; import javafx.scene.Group; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.paint.Color; import javafx.stage.Stage; public class Main extends Application { public static void main(String[] args) { launch(args); } private ExecutorService service = Executors.newSingleThreadExecutor(); private Time time; @Override public void start(Stage primaryStage) throws Exception { primaryStage.setResizable(false); // Parent parent = this.firstLawOfMotion(); // 等速直線運動 // Parent parent = this.secondLawOfMotion(); // 放物線運動 // Parent parent = this.circle(); // 円運動 // Parent parent = this.tension(); // 振り子 // Parent parent = this.universalGravitation1(); // 万有引力(冥王星 - カロン) // Parent parent = this.universalGravitation2(); // 万有引力(彗星) Parent parent = this.universalGravitation3(); // 万有引力(恒星 - 惑星 - 衛星) Scene root = new Scene(parent); primaryStage.setScene(root); primaryStage.show(); primaryStage.setOnCloseRequest(e -> { this.time.stop(); this.service.shutdown(); }); } /** * 運動の第1法則(等速直線運動) */ public Parent firstLawOfMotion() throws Exception { final double size = 100; // 実験空間の用意 Space space = new Space(size, new Camera()); space.add(new Axis(size)); // 世界を作り、ボールと物理法則を追加する World world = new World(); // ボール createBall() .location(80, 10, 10) .velocity(-5.0, 3.0, 6.0) .color(Color.BLUE) .appendTo(world, space); // 物理法則を作り、力はダミーを設定 ActingForce actingForce = new DummyForce(); PhysicalLaw law = new LawOfMotion(actingForce); // 軌跡 BallLocus locus = BallLocus.create(law).build(); space.add(locus); world.addPhysicalLaws(locus); // 時の流れをスタートさせる this.startTime(world, space); return new Group(space.getSubScene()); } /** * 運動の第2法則(運動方程式) */ public Parent secondLawOfMotion() throws Exception { final double size = 100; // 実験空間の用意 Space space = new Space(size, new Camera()); space.add(new Axis(size)); // 世界を作り、ボールと物理法則を追加する World world = new World(); // ボール createBall() .mass(10.0) .location(0.0, 0.0, 100.0) .velocity(12.5, 40.0, -12.5) .color(Color.BLUE) .appendTo(world, space); // 世界を作り、ボールと物理法則を追加する ActingForce actingForce = new EarthGravity(); PhysicalLaw law = new LawOfMotion(actingForce); // 軌跡 BallLocus locus = BallLocus.create(law).build(); space.add(locus); world.addPhysicalLaws(locus); // 時の流れをスタートさせる this.startTime(world, space); return new Group(space.getSubScene()); } /** * 円運動 */ public Parent circle() throws Exception { final double size = 100; // 実験空間の用意 Space space = new Space(size, new Camera()); space.add(new Axis(size)); // 世界を作り、ボールと物理法則を追加する World world = new World(); // ボール createBall() .mass(10.0) .location(50.0, 80.0, 25.0) .velocity(20.0, 0.0, 0.0) .color(Color.BLUE) .appendTo(world, space); // 物理法則を作り、力に向心力を設定 Point center = new Point(50.0, 50.0, 50.0); ActingForce actingForce = new CentripetalForce(center); PhysicalLaw law = new LawOfMotion(actingForce); // 軌跡 BallLocus locus = BallLocus.create(law).build(); space.add(locus); world.addPhysicalLaws(locus); // 時の流れをスタートさせる this.startTime(world, space); return new Group(space.getSubScene()); } /** * 振り子 */ public Parent tension() throws Exception { final double size = 100; // 実験空間の用意 Space space = new Space(size, new Camera()); space.add(new Axis(size)); // 世界を作り、ボールと物理法則を追加する World world = new World(); // ボール createBall() .mass(10.0) .location(80.0, 40.0, 20.0) .color(Color.BLUE) .appendTo(world, space); // 物理法則を作り、力に張力を設定 Point center = new Point(50.0, 100.0, 50.0); ActingForce actingForce = new Tension(center); PhysicalLaw law = new LawOfMotion(actingForce); // 軌跡 BallLocus locus = BallLocus.create(law).build(); space.add(locus); world.addPhysicalLaws(locus); // 時の流れをスタートさせる this.startTime(world, space); return new Group(space.getSubScene()); } /** * 万有引力(冥王星 - カロン) */ public Parent universalGravitation1() throws Exception { final double size = 100; // 一辺が 50,000 km になるように縮尺を設定 ViewPoint.setRate(size, 50_000.0); // 実験空間の用意 Space space = new Space(size, new Camera()); space.add(new Axis(size)); // 世界を作り、ボールと物理法則を追加する World world = new World(); // 冥王星 createBall() .mass(1.3 * Math.pow(10, 22)) .locationKm(25000, 25000, 25000) .velocityKm(0, 0, -0.02) .radius(2.0) .color(Color.RED) .appendTo(world, space); // カロン createBall() .mass(1.52 * Math.pow(10, 21)) .locationKm(25000 + 19571, 25000, 25000) .velocityKm(0, 0, 0.185) .radius(1.0) .color(Color.BLUE) .appendTo(world, space); // 物理法則を作り、力に万有引力を設定 ActingForce actingForce = new UniversalGravitation(world); PhysicalLaw law = new LawOfMotion(actingForce); // 軌跡 BallLocus locus = BallLocus.create(law) .historySize(100) .interval(100000) .radius(0.5) .build(); space.add(locus); world.addPhysicalLaws(locus); // 時の流れをスタートさせる this.startTime(world, space, 50000); return new Group(space.getSubScene()); } /** * 万有引力(彗星) */ public Parent universalGravitation2() throws Exception { final double size = 100; // 一辺が 50,000 km になるように縮尺を設定 ViewPoint.setRate(size, 50_000.0); // 実験空間の用意 Space space = new Space(size, new Camera()); space.add(new Axis(size)); // 世界を作り、ボールと物理法則を追加する World world = new World(); // 恒星 createBall() .mass(1.0 * Math.pow(10, 23)) .locationKm(25000, 25000, 25000) .velocityKm(0, 0, 0) .radius(5.0) .color(Color.RED) .appendTo(world, space); // 彗星 createBall() .mass(1.0 * Math.pow(10, 10)) .locationKm(50000, 50000, 50000) .velocityKm(-0.1, 0, 0.2) .radius(1.0) .color(Color.BLUE) .appendTo(world, space); // 物理法則を作り、力に万有引力を設定 ActingForce actingForce = new UniversalGravitation(world); PhysicalLaw law = new LawOfMotion(actingForce); // 軌跡 BallLocus locus = BallLocus.create(law) .historySize(100) .interval(100000) .radius(0.5) .build(); space.add(locus); world.addPhysicalLaws(locus); // 時の流れをスタートさせる this.startTime(world, space, 50000); return new Group(space.getSubScene()); } /** * 万有引力(恒星 - 惑星 - 衛星) */ public Parent universalGravitation3() throws Exception { final double size = 100; // 一辺が 30,000,000km になるように縮尺を設定 ViewPoint.setRate(size, 30_000_000); // 実験空間の用意 Space space = new Space(size, new Camera()); space.add(new Axis(size)); // 世界を作り、ボールと物理法則を追加する World world = new World(); // 恒星 createBall() .mass(1.0 * Math.pow(10, 30)) .locationKm(15_000_000, 15_000_000, 15_000_000) .velocityKm(0, 0, 0) .radius(5.0) .color(Color.RED) .appendTo(world, space); // 惑星 createBall() .mass(1.8986 * Math.pow(10, 27)) .locationKm(30_000_000, 15_000_000, 15_000_000) .velocityKm(0, 0, -67) .radius(0.5) .color(Color.BLUE) .appendTo(world, space); // 衛星 createBall() .mass(8.9 * Math.pow(10, 22)) .locationKm(29_600_000, 15_000_000, 15_000_000) .velocityKm(0, 0, -50) .radius(0.4) .color(Color.YELLOW) .appendTo(world, space); // 物理法則を作り、力に万有引力を設定 ActingForce actingForce = new UniversalGravitation(world); PhysicalLaw law = new LawOfMotion(actingForce); // 軌跡 BallLocus locus = BallLocus.create(law) .historySize(100) .color(Color.GRAY) .interval(100000) .radius(0.2) .build(); space.add(locus); world.addPhysicalLaws(locus); // 時の流れをスタートさせる this.startTime(world, space, 50000); return new Group(space.getSubScene()); } private void startTime(World world, Space space) { this.startTime(world, space, 1); } private void startTime(World world, Space space, int speed) { this.time = new Time(world, speed); this.time.setTick(() -> { space.refresh(); }); this.service.execute(() -> { try { Thread.sleep(500); // 何故かマウスドラッグが効かなくなることがある } catch (Exception e) { e.printStackTrace(); } this.time.start(); }); } private static BallAppender createBall() { return new BallAppender(); } static class BallAppender { private Mass mass = new Mass(10.0); private Point location = Point.ORIGIN; private Velocity velocity = Velocity.ZERO; private double radius = 1.0; private Color color = Color.WHITE; public BallAppender mass(double mass) { this.mass = new Mass(mass); return this; } public BallAppender location(double x, double y, double z) { this.location = new Point(x, y, z); return this; } public BallAppender locationKm(double x, double y, double z) { return this.location(x * 1000.0, y * 1000.0, z * 1000.0); } public BallAppender velocity(double x, double y, double z) { this.velocity = new Velocity(x, y, z); return this; } public BallAppender velocityKm(double x, double y, double z) { return this.velocity(x * 1000.0, y * 1000.0, z * 1000.0); } public BallAppender radius(double radius) { this.radius = radius; return this; } public BallAppender color(Color color) { this.color = color; return this; } public void appendTo(World world, Space space) { Ball ball = new Ball(this.mass); ball.setLocation(this.location); ball.setVelocity(this.velocity); BallShape shape = new BallShape(ball, this.radius, this.color); world.addPhysical(ball); space.add(shape); } } }