1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package sample;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class _suzuka_circuit extends Application {
	public static void main(String... args) {
		Application.launch(args);
	}
	private static final int VIEW_W = 400, VIEW_H = 300;
	private GraphicsContext gc;
	@Override
	public void start(Stage stage) throws Exception {
		BorderPane pane = new BorderPane();
		Scene scene = new Scene(pane);
		stage.setScene(scene);
		Canvas view = new Canvas(VIEW_W, VIEW_H);
		pane.setCenter(view);
		gc = view.getGraphicsContext2D();
		draw();
		stage.show();
	}
	private double[][] circuit = {
		{60, 15, -15}, {20}, {4, 180},
		{4, -30}, {4, 60}, {4, -60}, {4, 60}, {4, -105}, {15},
		{4, 135}, {30}, {6, 15}, {10},
		{3, -180}, {15}, {15, 120}, {6, -225}, {20}, {15, -15},
	};
	private double curr_x, curr_y, curr_a;
	private static final double MIN_A = 5, MAX_A = 270, MIN_R = 2;
	private static final String
		ERR_A = "最終コーナーの角度が範囲外",
		ERR_R = "最終コーナーの半径が小さい",
		ERR_L = "最終ストレートの距離がマイナス"
	;
	private void draw() {
		gc.setTransform(4, 0, 0, 4, 0, 0);
		double[] part = circuit[0];
		double start_x = part[0], start_y = part[1], start_a = part[2];
		curr_x = start_x; curr_y = start_y; curr_a = start_a;
		gc.beginPath();
		gc.moveTo(curr_x, curr_y);
		for (int i = 1; i < circuit.length; i++)
			draw_circuit_part(circuit[i]);
		// 最終ストレートとコーナーを求める
		double dx = start_x - curr_x, dy = start_y - curr_y;
		double l = dx * my_cos(curr_a) + dy * my_sin(curr_a);
		double r = dx * my_cos(curr_a + 90) + dy * my_sin(curr_a + 90);
		double sign = Math.signum(r);
		double da = Math.abs(start_a - curr_a);
		if ((curr_a > start_a) == (sign > 0))
			da = 360 - da;
		if (da < MIN_A || da > MAX_A)
			throw new InternalError(ERR_A);
		r = Math.abs(r) / (1 - my_cos(da));
		if (r < MIN_R)
			throw new InternalError(ERR_R);
		l -= r * my_sin(da);
		if (l < 0)
			throw new InternalError(ERR_L);
		draw_circuit_part(l);
		draw_circuit_part(r, sign * da);
		gc.stroke();
	}
	private void draw_circuit_part(double... part) {
		if (part.length == 1) { // ストレート
			double l = part[0];
			curr_x += l * my_cos(curr_a);
			curr_y += l * my_sin(curr_a);
		}
		else if (part.length == 2) { // コーナー
			double r = part[0];
			double da = part[1];
			double sign = Math.signum(da);
			double center_x = curr_x + sign * r * my_cos(curr_a + 90);
			double center_y = curr_y + sign * r * my_sin(curr_a + 90);
			gc.arc(center_x, center_y, r, r, sign * 90 - curr_a, -da);
			curr_a += da;
			curr_x = center_x + r * my_cos(curr_a - sign * 90);
			curr_y = center_y + r * my_sin(curr_a - sign * 90);
		}
	}
	private static final double RAD = Math.PI / 180;
	private double my_sin(double a) { return Math.sin(a * RAD); }
	private double my_cos(double a) { return Math.cos(a * RAD); }
}