import java.util.concurrent.BlockingQueue; import com.sun.javafx.runtime.async.AbstractAsyncOperation; import com.sun.javafx.runtime.async.AsyncOperationListener; public class MandelbrotWorker extends AbstractAsyncOperation<Object> { // イベントディスパッチスレッドと居有するキュー // スレッドセーフなBlockingQueueインタフェースを使用する private BlockingQueue<Point> queue; public MandelbrotWorker(BlockingQueue<Point> queue, AsyncOperationListener<Object> listener) { super(listener); // イベントディスパッチスレッドとキューを共有 this.queue = queue; } // 非同期に行う処理 @Override public Object call() throws InterruptedException { for (double x = -2.0; x <= 0.6; x += 0.005) { for (double y = -1.2; y <= 1.2; y += 0.005) { Point c = new Point(x, y, 0); Point z = new Point(0.0, 0.0, 0); while (true) { // 漸化式の計算 z = calcNextPoint(z, c); // zの大きさが100,000以上であれば無限大と見なす // また、215回以上のイテレーションを繰り返しても // 100,000以上にならなければマンデルブロ集合に属していると見なす if (z.length() > 100000 || z.number > 215) { break; } } // イテレーション数をコピーする c.number = z.number; // 計算結果をキューに入れる queue.put(c); } } return null; } // マンデルブロの漸化式 private Point calcNextPoint(Point z, Point c) { double x = z.x * z.x - z.y * z.y + c.x; double y = 2 * z.x * z.y + c.y; return new Point(x, y, z.number + 1); } }
// マンデルブロの計算結果を格納するクラス public class Point { public double x; public double y; // 無限大と見なしたイテレーション回数 // 最大215回とする public int number; public Point(double x, double y, int number) { this.x = x; this.y = y; this.number = number; } public double length() { return x * x + y * y; } }
import javafx.async.AbstractAsyncOperation; import java.lang.Object; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import com.sun.javafx.runtime.async.AsyncOperationListener; public class Mandelbrot extends AbstractAsyncOperation { // スレッド間でデータを受け渡しするキュー // スレッドセーフなBlockingQueueインタフェースを使用する var queue: BlockingQueue; // 非同期処理を行うJavaクラス var worker: MandelbrotWorker; public override function start(): Void { // スレッド間の計算結果の引渡しにキューを使用する // BlockingQueueインタフェースのコンクリートクラスとして // LinkedBlockingQueueクラスを使用する queue = new LinkedBlockingQueue(); // Javaの非同期処理部分 worker = new MandelbrotWorker(queue, listener); // 非同期処理の開始 worker.start(); } public override function cancel(): Void { // 非同期処理のキャンセル worker.cancel(); } public override function onCompletion(value: Object): Void {} // キューから計算結果を取り出す public function poll(): Point { queue.poll() as Point; } }
import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.ext.swing.SwingButton; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.stage.Stage; import java.awt.image.BufferedImage; // 色のインデックス var colors: Integer[] = for(i in [0..7]) { for (blue in [0, 0x66, 0xff], green in [0, 0x66, 0xff], red in [0, 0x66,0xff]) { var color = (0xff - red) * 0x10000 + (0xff - green) * 0x100 + (0xff - blue); } } // Imageクラスはピクセルにアクセスできないので、BufferedImageクラスを使用する var bufferedImage: BufferedImage; var image: Image; // 非同期でマンデルブロの計算を行うクラス var mandelbrot: Mandelbrot; // 非同期で行われる処理から結果を受け取るためのタイムライン var timeline: Timeline; timeline = Timeline { repeatCount: Timeline.INDEFINITE keyFrames: [ KeyFrame { time: 0.0s action: function() { while(true) { // キューから計算結果の取り出し var point = mandelbrot.poll(); if (point != null) { // 計算結果からイメージに色をセットする var x = (point.x * 200 + 400) as Integer; var y = (point.y * 200 + 240) as Integer; var color = colors[point.number]; bufferedImage.setRGB(x, y, color); } else { // キューが空であれば、0.1秒待つ break; } } // BufferedImageからImageオブジェクトを生成する image = Image.fromBufferedImage(bufferedImage); } }, KeyFrame { time: 0.1s action: function() { // 非同期処理が終了していたら、timelineもストップさせる if (mandelbrot.done) { timeline.stop(); } } } ] } Stage { title: "Mandelbrot" scene: Scene { width: 520 height: 480 fill: Color.BLACK content: [ ImageView { image: bind image }, SwingButton { text: "DRAW" action: function() { timeline.stop(); if (mandelbrot != null) { // 非同期で処理を行っている場合はキャンセル mandelbrot.cancel(); } // イメージとMandelbrotオブジェクトを新たに生成し、 // 非同期処理を開始する bufferedImage = new BufferedImage(520, 480, BufferedImage.TYPE_INT_RGB); mandelbrot = Mandelbrot {}; timeline.play(); } } ] } }