1. 程式人生 > >tornadofx使用circle、AnimationTimer、timeline動畫演示蒙特卡洛演算法求PI值

tornadofx使用circle、AnimationTimer、timeline動畫演示蒙特卡洛演算法求PI值

演示地址https://www.bilibili.com/video/av59421525

import javafx.animation.AnimationTimer
import javafx.scene.paint.Color
import javafx.scene.shape.Circle
import javafx.util.Duration
import tornadofx.*

class 蒙特卡洛演算法 : App(蒙特卡洛演算法求Pi::class)
class 蒙特卡洛演算法求Pi : View("learn 蒙特卡洛演算法") {

    //    動畫計時器
    val aniTimer = AniTimer(this)
    val result = stringProperty()
    val numPoint = intProperty()
    val Msg = stringProperty()
    val numPointInCircle = intProperty()
    lateinit var circle0: Circle
    override val root = borderpane {
        top = vbox(5) {
            label(result) {
                isWrapText = true
            }
            label(Msg)
            hbox(5) {
                button("run").action {
                    //                ani()
                    aniTimer.start()
                }
                button("stop").action {
                    //                ani()
                    aniTimer.stop()
                }
            }
        }
        center = group {
            rectangle(0, 0, 600, 600) {
                fill = Color.YELLOW
            }
            circle0 = circle(300, 300, 300) {
                fill = Color.AZURE
            }
            prefHeight = 800.0
            prefWidth = 800.0
        }
    }

    fun paint() {
        timeline {
            keyframe(Duration.seconds(0.0010)) {
                //  用迴圈包裹,可以調節繪製速度
                (0..100).forEach {
                    val p = point((0..600).random().toDouble(), (0..600).random().toDouble())
                    val c = Circle(p.x, p.y, 1.0)
//                判斷圓circle0是否包含點p,方法1
//                val b = ((p.x - circle0.centerX).pow(2).plus((p.y - circle0.centerY).pow(2)) <= circle0.radius.pow(2))
//                if (b) {
//                    c.fill = Color.RED
//                }
                    //  判斷圓circle0是否包含點p,方法2
                    if (circle0.contains(p)) {
                        c.fill = Color.RED
                        numPointInCircle.value++
                    }
                    root.center.add(c)
                    numPoint.value++
                    val piEstimate = 4.0 * numPointInCircle.value/ numPoint.value
                    Msg.value = "總點數:${numPoint.value} -- 圓內點數:${numPointInCircle.value} -- Pi估計值:  ${piEstimate} "
                }
            }
        }
    }

    // 此方法可以停止動畫
    class AniTimer(val learnV: 蒙特卡洛演算法求Pi) : AnimationTimer() {
        var lastTime = 0L
        override fun handle(now: Long) {
            if ((now - lastTime) > 10000000) {
                lastTime = now
            } else {
                return
            }
            learnV.paint()
        }
    }
}

控制檯輸出版本:

import javafx.scene.paint.Color
import javafx.scene.shape.Circle
import tornadofx.*



fun main(){
    // 矩形邊長
    val recWidth=1000
    val r=recWidth/2.toDouble()
    val circle0 = Circle(r, r.toDouble(), r)

//    總點數
    val numPoint = intProperty()
//    圓內點數
    val numPointInCircle = intProperty()
    val Msg = stringProperty()

//    1000萬個點
    val n=10000000
    (0..n).forEach {
        val p = point((0..recWidth).random().toDouble(), (0..recWidth).random().toDouble())
        val c = Circle(p.x, p.y, 1.0)
//                判斷圓circle0是否包含點p,方法1
//                val b = ((p.x - circle0.centerX).pow(2).plus((p.y - circle0.centerY).pow(2)) <= circle0.radius.pow(2))
//                if (b) {
//                    c.fill = Color.RED
//                }
        //  判斷圓circle0是否包含點p,方法2
        if (circle0.contains(p)) {
            c.fill = Color.RED
            numPointInCircle.value++
        }
        numPoint.value++
        val piEstimate = 4.0 * numPointInCircle.value/ numPoint.value
//        每隔1萬個點輸出一次
        if(numPoint.value/10000==1){
            Msg.value = "總點數:${numPoint.value} -- 圓內點數:${numPointInCircle.value} -- Pi估計值:  ${piEstimate} "
            println(Msg.value)
        }
    }
}