野火通过燃床蔓延是自然界的一个复杂现象.本文综述了为认识这一现象所作的研究工作,包括分析各种理化机制及通过基本物理规律构造数学模型。现有的数学模型可分为统计模型、经验模型和物理模型三类.本文着重以统一的观点评述了近五十年来所建立的各种物理模型,并讨论了考虑湍流热对流和化学反应动力学的新方向.
本问通过用js模拟野火蔓延效果来实现一个可视化的蔓延展示:
![](https://img-blog.csdnimg.cn/img_convert/9ce4a44c40723d70ddb7406d32a35dd5.gif)
点击草原上点可以点燃火苗,旋转的箭头表明风的方向。
在线demo地址
index.html
<!doctype html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fire</title>
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="tools" style="width: 750px; position: relative; height: 5em;">
<div style="position: absolute; left: 0; top: 0;">
<button class="ignite">燃烧</button>
<button class="firebreak">防火隔离带</button>
<div class="compass">
<div class="wind"></div>
</div>
</div>
<div style="position: absolute; right: 0; top: 0;">
<span id="fps" style="color: #000; font-weight: bold; margin-right: 1em;">
<span class="model"></span>
+
<span class="view"></span>
</span>
<button id="reset-button">重置</button>
</div>
</div>
<div id="burned">
<div></div>
</div>
<div id="grid">
</div>
<script src="main.js" type="module"></script>
</body>
main.js
import { FireGrid } from './lib/FireGrid.js';
import { FireGridView } from './lib/FireGridView.js';
import { FireGridControl } from './lib/FireGridControl.js';
const width = 375;
const height = 375;
const scale = 2;
const container = document.querySelector('#grid');
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
canvas.id = 'fire-grid';
container.appendChild(canvas);
/*
const target = document.createElement('div');
target.className = 'target';
container.appendChild(target);
*/
const dom = {
grid: document.querySelector('#fire-grid'),
target: document.querySelector('#grid .target'),
reset: document.querySelector('#reset-button'),
burned: document.querySelector('#burned div'),
burnedAmount: document.querySelector('#burned div'),
toolIgnite: document.querySelector('#tools .ignite'),
toolFirebreak: document.querySelector('#tools .firebreak'),
};
const toolModes = {
ignite: 0,
firebreak: 1,
}
let toolMode = toolModes.ignite;
updateTools();
dom.toolIgnite.addEventListener('click', function () {
toolMode = toolModes.ignite;
updateTools();
});
dom.toolFirebreak.addEventListener('click', function () {
toolMode = toolModes.firebreak;
updateTools();
});
function updateTools () {
if (toolMode === toolModes.ignite) {
dom.toolIgnite.classList.add('selected');
dom.toolFirebreak.classList.remove('selected');
} else if (toolMode === toolModes.firebreak) {
dom.toolIgnite.classList.remove('selected');
dom.toolFirebreak.classList.add('selected');
}
}
const fireGrid = new FireGrid(width, height);
const fgView = new FireGridView(width, height, dom.grid);
const fgControl = new FireGridControl(fireGrid, fgView);
let lastTime = +new Date();
function handleMouse (event) {
const rect = dom.grid.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
//const x = event.layerX;
//const y = event.layerY;
const row = Math.floor(y/scale);// scale);
const col = Math.floor(x/scale);// scale);
if (toolMode === toolModes.ignite) {
fgControl.ignite(row, col);
} else if (toolMode === toolModes.firebreak) {
fgControl.firebreak(row, col);
}
}
dom.grid.addEventListener('click', handleMouse);
dom.reset.addEventListener('click', () => {
fgControl.reset();
});
function step () {
const now = +new Date();
const duration = now - lastTime;
lastTime = now;
fgControl.step(duration);
const width = String(Math.round(fgControl.burned * 100)) + '%';
dom.burnedAmount.style.width = width;
dom.burned.innerHTML = width;
window.requestAnimationFrame(step);
}
step();