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 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
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.scene.shape.ArcType; import javafx.stage.Stage; public class _boar extends Application { public static void main(String... args) { Application.launch(args); } private static final int VIEW_W = 400, VIEW_H = 300; private GraphicsContext gc; private static final double LINE_WIDTH = 3; // 線の太さ private static final int CX = 250, CY = 160; // 座標中心 private static final double HR = 135; // 頭部の半径 private static final double[] hair1 = {0.5, 0.5, 1.25, 0.5}, hair2 = {1.0, .25, 1.0, 0.0}; @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 void draw() { reset_transform(); gc.setLineWidth(LINE_WIDTH); // 頭部の輪郭 gc.strokeArc(-HR, -HR, 2 * HR, 2 * HR, 30, -120, ArcType.OPEN); gc.strokeArc(-HR, -HR, 2 * HR, 2 * HR, 120, -60, ArcType.OPEN); // 口 double mouth_x = HR * my_cos(-150), mouth_y = HR * my_sin(-150); double maxi_x = mouth_x - HR * 0.8, maxi_y = 0; gc.strokeLine(maxi_x, mouth_y, mouth_x, mouth_y); // 上顎 double head_x1 = HR * my_cos(135), head_y1 = HR * my_sin(135); double dy = head_y1 - maxi_y; gc.moveTo(maxi_x, mouth_y); bezier(maxi_x - 10, maxi_y + 10, maxi_x, maxi_y, maxi_x + 10, maxi_y); bezier(head_x1 - dy, maxi_y, head_x1, head_y1); gc.stroke(); // 下顎 double head_x2 = HR * my_cos(-120), head_y2 = HR * my_sin(-120); double chin_x = mouth_x - HR * 0.5, chin_y = HR * my_sin(-135); dy = chin_y - head_y2; gc.moveTo(chin_x, mouth_y); bezier(chin_x, chin_y, chin_x + 40, chin_y); bezier(head_x2 - dy * my_tan(60), chin_y, head_x2, head_y2); gc.stroke(); // 目 gc.strokeOval(-HR * 0.5 - 10, 10, 20, 20); // 牙 double k = HR * 0.25; gc.setLineWidth(LINE_WIDTH / k); reset_transform(); gc.transform(k, 0, 0, k, mouth_x, mouth_y); gc.rotate(15); gc.moveTo(0, 0); bezier(0.25, 1, 0.625, 2); bezier(0.75, 1, 1, 0); bezier(0.5, -0.125, 0, 0); gc.stroke(); // 耳 k = HR * 0.375; gc.setLineWidth(LINE_WIDTH / k); reset_transform(); gc.transform(k, 0, 0, k, 0, HR * 0.5); gc.rotate(-30); gc.moveTo(0, 0); bezier(0.25, 0.5, 0, 1); bezier(1, 1, 1, 0); bezier(0.5, 0.125, 0, 0); // 上の毛 k = HR * my_sin(15) / my_sin(82.5); gc.setLineWidth(LINE_WIDTH / k); reset_transform(); gc.transform(k, 0, 0, k, head_x1, head_y1); gc.rotate(45 - 7.5); gc.moveTo(0, 0); for (int i = 0; i < 3; i++) { bezier(hair1); bezier(hair2); gc.translate(1, 0); gc.rotate(-15); } gc.stroke(); // 下の毛 reset_transform(); gc.transform(-k, 0, 0, k, HR * my_cos(-60), HR * my_sin(-60)); gc.rotate(150 - 7.5); gc.moveTo(0, 0); for (int i = 0; i < 2; i++) { bezier(hair1); bezier(hair2); gc.translate(1, 0); gc.rotate(-15); } gc.stroke(); } private void reset_transform() { gc.setTransform(1, 0, 0, -1, CX, CY); } private void bezier(double... pa) { if (pa.length == 4) gc.quadraticCurveTo(pa[0], pa[1], pa[2], pa[3]); else if (pa.length == 6) gc.bezierCurveTo(pa[0], pa[1], pa[2], pa[3], pa[4], pa[5]); } private static final double DEG = Math.PI / 180; // ラジアン private static final double my_sin(double t) { return Math.sin(t * DEG); } private static final double my_cos(double t) { return Math.cos(t * DEG); } private static final double my_tan(double t) { return Math.tan(t * DEG); } }