Merge branch 'master' of gitorious.org:fg/fgdata into Work
This commit is contained in:
commit
91ab9b540d
1 changed files with 115 additions and 52 deletions
|
@ -8,7 +8,7 @@
|
|||
##
|
||||
###############################################################################
|
||||
|
||||
# The cellular automata model used here is based on
|
||||
# The cellular automata model used here is loosely based on
|
||||
# A. Hernandez Encinas, L. Hernandez Encinas, S. Hoya White,
|
||||
# A. Martin del Rey, G. Rodriguez Sanchez,
|
||||
# "Simulation of forest fire fronts using cellular automata",
|
||||
|
@ -134,7 +134,7 @@ var models_enabled_pp = "environment/wildfire/models/enabled";
|
|||
var fire_LOD_pp = "environment/wildfire/models/fire-lod";
|
||||
var smoke_LOD_pp = "environment/wildfire/models/smoke-lod";
|
||||
var LOD_High = 20;
|
||||
var LOD_Low = 80;
|
||||
var LOD_Low = 50;
|
||||
var mp_last_limited_event = {}; # source : time
|
||||
|
||||
var score = { extinguished : 0, protected : 0, waste : 0 };
|
||||
|
@ -202,7 +202,7 @@ var parse_msg = func (source, msg) {
|
|||
var pos = Binary.decodeCoord(substr(msg, 6));
|
||||
ignite(pos, 0);
|
||||
} else {
|
||||
printlog("warn", "wildfire.nas: Ignored ignite event from " ~
|
||||
printlog("alert", "wildfire.nas: Ignored ignite event flood from " ~
|
||||
source.getNode("callsign").getValue());
|
||||
}
|
||||
mp_last_limited_event[i] = cur_time;
|
||||
|
@ -240,13 +240,13 @@ var SimTime = {
|
|||
}
|
||||
};
|
||||
|
||||
###############################################################################
|
||||
# Class that maintains one fire cell.
|
||||
|
||||
###############################################################################
|
||||
# Class that maintains the state of one fire cell.
|
||||
var FireCell = {
|
||||
############################################################
|
||||
new : func (x, y) {
|
||||
# print("Creating FireCell[" ~ x ~ "," ~ y ~ "]");
|
||||
trace("Creating FireCell[" ~ x ~ "," ~ y ~ "]");
|
||||
var m = { parents: [FireCell] };
|
||||
m.lat = y * CAFire.CELL_SIZE/60.0 + 0.5 * CAFire.CELL_SIZE / 60.0;
|
||||
m.lon = x * CAFire.CELL_SIZE/60.0 + 0.5 * CAFire.CELL_SIZE / 60.0;
|
||||
|
@ -269,7 +269,7 @@ var FireCell = {
|
|||
m.burn_rate = CAFire.BURN_RATE[mat];
|
||||
}
|
||||
}
|
||||
m.model = CellModel.new(x, y, m.alt);
|
||||
CAFireModels.add(x, y, m.alt);
|
||||
append(CAFire.active, m);
|
||||
CAFire.cells_created += 1;
|
||||
return m;
|
||||
|
@ -280,7 +280,7 @@ var FireCell = {
|
|||
trace("FireCell[" ~ me.x ~ "," ~me.y ~ "] Ignited!");
|
||||
me.burning[CAFire.next] = 1;
|
||||
me.burning[CAFire.old] = 1;
|
||||
me.model.set_type("fire");
|
||||
CAFireModels.set_type(me.x, me.y, "fire");
|
||||
# Prevent update() on this cell in this generation.
|
||||
me.last = CAFire.generation;
|
||||
} else {
|
||||
|
@ -300,16 +300,16 @@ var FireCell = {
|
|||
# Prevent update() on this cell in this generation.
|
||||
me.last = CAFire.generation;
|
||||
if ((me.state[CAFire.old] > 0.0) and (me.burning[CAFire.old] > 0)) {
|
||||
me.model.set_type("soot");
|
||||
CAFireModels.set_type(me.x, me.y, "soot");
|
||||
} else {
|
||||
# Use a model representing contamination here.
|
||||
me.model.set_type(type);
|
||||
CAFireModels.set_type(me.x, me.y, type);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
############################################################
|
||||
update : func () {
|
||||
# print("FireCell[" ~ me.x ~ "," ~me.y ~ "] " ~ me.state[CAFire.old]);
|
||||
trace("FireCell[" ~ me.x ~ "," ~me.y ~ "] " ~ me.state[CAFire.old]);
|
||||
if ((me.state[CAFire.old] == 1) and (me.burning[CAFire.old] == 0))
|
||||
return 0;
|
||||
if ((me.burn_rate == 0) and (me.burning[CAFire.old] == 0))
|
||||
|
@ -337,7 +337,7 @@ var FireCell = {
|
|||
return 0;
|
||||
}
|
||||
me.burning[CAFire.next] = me.burning[CAFire.old];
|
||||
me.model.set_type(me.burning[CAFire.old] ? "fire" : "soot");
|
||||
CAFireModels.set_type(me.x, me.y, me.burning[CAFire.old] ? "fire" : "soot");
|
||||
return 1;
|
||||
},
|
||||
############################################################
|
||||
|
@ -402,13 +402,13 @@ var CellModel = {
|
|||
me.model = nil;
|
||||
}
|
||||
me.type = type;
|
||||
if (CAFire.MODEL[type] == "") return;
|
||||
if (CAFireModels.MODEL[type] == "") return;
|
||||
|
||||
# Always put "cheap" models for now.
|
||||
if (CAFire.models_enabled or (type != "fire")) {
|
||||
if (CAFireModels.models_enabled or (type != "fire")) {
|
||||
me.model =
|
||||
geo.put_model(CAFire.MODEL[type], me.lat, me.lon, me.alt);
|
||||
# print("Created 3d model " ~ type ~ " " ~ CAFire.MODEL[type]);
|
||||
geo.put_model(CAFireModels.MODEL[type], me.lat, me.lon, me.alt);
|
||||
trace("Created 3d model " ~ type ~ " " ~ CAFireModels.MODEL[type]);
|
||||
}
|
||||
},
|
||||
############################################################
|
||||
|
@ -420,7 +420,95 @@ var CellModel = {
|
|||
};
|
||||
|
||||
###############################################################################
|
||||
# Singleton that maintains the fire CA grid.
|
||||
# Singleton that maintains the CA models.
|
||||
var CAFireModels = {};
|
||||
# Constants
|
||||
CAFireModels.MODEL = { # Model paths
|
||||
"fire" : "Models/Effects/Wildfire/wildfire.xml",
|
||||
"soot" : "Models/Effects/Wildfire/soot.xml",
|
||||
"foam" : "Models/Effects/Wildfire/foam.xml",
|
||||
"water" : "",
|
||||
"protected" : "",
|
||||
"none" : "",
|
||||
};
|
||||
# State
|
||||
CAFireModels.grid = {}; # Sparse cell model grid storage.
|
||||
CAFireModels.pending = []; # List of pending model changes.
|
||||
CAFireModels.models_enabled = 1;
|
||||
CAFireModels.loopid = 0;
|
||||
######################################################################
|
||||
# Public operations
|
||||
############################################################
|
||||
CAFireModels.init = func {
|
||||
# Initialization.
|
||||
setlistener(models_enabled_pp, func (n) {
|
||||
me.set_models_enabled(n.getValue());
|
||||
}, 1);
|
||||
me.reset(1);
|
||||
}
|
||||
############################################################
|
||||
# Reset the model grid to the empty state.
|
||||
CAFireModels.reset = func (enabled) {
|
||||
# Clear the model grid.
|
||||
foreach (var x; keys(me.grid)) {
|
||||
foreach (var y; keys(me.grid[x])) {
|
||||
if (me.grid[x][y] != nil) me.grid[x][y].remove();
|
||||
}
|
||||
}
|
||||
# Reset state.
|
||||
me.grid = {};
|
||||
me.pending = [];
|
||||
|
||||
me.loopid += 1;
|
||||
me._loop_(me.loopid);
|
||||
}
|
||||
############################################################
|
||||
# Add a new cell model.
|
||||
CAFireModels.add = func(x, y, alt) {
|
||||
append(me.pending, { x: x, y: y, alt: alt });
|
||||
}
|
||||
############################################################
|
||||
# Update a cell model.
|
||||
CAFireModels.set_type = func(x, y, type) {
|
||||
append(me.pending, { x: x, y: y, type: type });
|
||||
}
|
||||
############################################################
|
||||
CAFireModels.set_models_enabled = func(on=1) {
|
||||
me.models_enabled = on;
|
||||
# We should do a pass over all cells here to add/remove models.
|
||||
# For now I don't so only active cells will actually remove the
|
||||
# models. All models will be hidden by their select animations, though.
|
||||
}
|
||||
######################################################################
|
||||
# Private operations
|
||||
############################################################
|
||||
CAFireModels.update = func {
|
||||
var work = size(me.pending)/10;
|
||||
while (size(me.pending) > 0 and work > 0) {
|
||||
var c = me.pending[0];
|
||||
me.pending = subvec(me.pending, 1);
|
||||
work -= 1;
|
||||
if (contains(c, "alt")) {
|
||||
if (me.grid[c.x] == nil) {
|
||||
me.grid[c.x] = {};
|
||||
}
|
||||
me.grid[c.x][c.y] = CellModel.new(c.x, c.y, c.alt);
|
||||
}
|
||||
if (contains(c, "type")) {
|
||||
me.grid[c.x][c.y].set_type(c.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
############################################################
|
||||
CAFireModels._loop_ = func(id) {
|
||||
id == me.loopid or return;
|
||||
me.update();
|
||||
settimer(func { me._loop_(id); }, 0);
|
||||
}
|
||||
###############################################################################
|
||||
|
||||
###############################################################################
|
||||
# Singleton that maintains the fire cell CA grid.
|
||||
var CAFire = {};
|
||||
# State
|
||||
CAFire.CELL_SIZE = 0.03; # "nm" (or rather minutes)
|
||||
|
@ -466,14 +554,6 @@ CAFire.BURN_RATE = { # Burn rate DB. grid widths per second
|
|||
# ?
|
||||
"Landmass" : 0.0005
|
||||
};
|
||||
CAFire.MODEL = { # Model paths
|
||||
"fire" : "Models/Effects/Wildfire/wildfire.xml",
|
||||
"soot" : "Models/Effects/Wildfire/soot.xml",
|
||||
"foam" : "Models/Effects/Wildfire/foam.xml",
|
||||
"water" : "",
|
||||
"protected" : "",
|
||||
"none" : "",
|
||||
};
|
||||
CAFire.NEIGHBOURS = # Neighbour index offsets. First row and column
|
||||
# and then diagonal.
|
||||
[[[-1, 0], [0, 1], [1, 0], [0, -1]],
|
||||
|
@ -483,21 +563,13 @@ CAFire.NEIGHBOURS = # Neighbour index offsets. First row and column
|
|||
############################################################
|
||||
CAFire.init = func {
|
||||
# Initialization.
|
||||
setlistener(models_enabled_pp, func (n) {
|
||||
me.set_models_enabled(n.getValue());
|
||||
}, 1);
|
||||
me.reset(1, SimTime.current_time());
|
||||
}
|
||||
############################################################
|
||||
# Reset the CA to the empty state and set its current time to sim_time.
|
||||
CAFire.reset = func (enabled, sim_time) {
|
||||
# Clear the grid.
|
||||
foreach (var x; keys(me.grid)) {
|
||||
foreach (var y; keys(me.grid[x])) {
|
||||
if (me.grid[x][y].model != nil) me.grid[x][y].model.remove();
|
||||
me.grid[x][y] = nil;
|
||||
}
|
||||
}
|
||||
# Clear the model grid.
|
||||
CAFireModels.reset(enabled);
|
||||
# Reset state.
|
||||
me.grid = {};
|
||||
me.generation = int(sim_time/CAFire.GENERATION_DURATION);
|
||||
|
@ -518,7 +590,7 @@ CAFire.reset = func (enabled, sim_time) {
|
|||
############################################################
|
||||
# Start a fire in the cell at pos.
|
||||
CAFire.ignite = func (lat, lon) {
|
||||
# print("Fire at " ~ lat ~", " ~ lon ~ ".");
|
||||
trace("CAFire.ignite: Fire at " ~ lat ~", " ~ lon ~ ".");
|
||||
var x = int(lon*60/me.CELL_SIZE);
|
||||
var y = int(lat*60/me.CELL_SIZE);
|
||||
var cell = me.get_cell(x, y);
|
||||
|
@ -537,17 +609,16 @@ CAFire.ignite = func (lat, lon) {
|
|||
# radius - meter : double
|
||||
# Note: volume is unused ATM.
|
||||
CAFire.resolve_water_drop = func (lat, lon, radius, volume=0) {
|
||||
trace("CAFire.resolve_water_drop: Dumping water at " ~ lat ~", " ~ lon ~
|
||||
" radius " ~ radius ~".");
|
||||
var x = int(lon*60/me.CELL_SIZE);
|
||||
var y = int(lat*60/me.CELL_SIZE);
|
||||
var r = int(2*radius/(me.CELL_SIZE*1852.0));
|
||||
# print("Dumping water at " ~ lat ~", " ~ lon ~
|
||||
# ". Center (" ~ x ~ "," ~ y ~ ") radius " ~ r ~".");
|
||||
var result = { extinguished : 0, protected : 0, waste : 0 };
|
||||
for (var dx = -r; dx <= r; dx += 1) {
|
||||
for (var dy = -r; dy <= r; dy += 1) {
|
||||
var cell = me.get_cell(x + dx, y + dy);
|
||||
if (cell == nil) {
|
||||
# print(" (" ~ (x + dx) ~ ", " ~ (y + dy) ~ ")");
|
||||
cell = FireCell.new(x + dx, y + dy);
|
||||
me.set_cell(x + dx, y + dy,
|
||||
cell);
|
||||
|
@ -584,17 +655,16 @@ CAFire.resolve_retardant_drop = func (lat, lon, radius, volume=0) {
|
|||
# radius - meter : double
|
||||
# Note: volume is unused ATM.
|
||||
CAFire.resolve_foam_drop = func (lat, lon, radius, volume=0) {
|
||||
trace("CAFire.resolve_foam_drop: Dumping foam at " ~ lat ~", " ~ lon ~
|
||||
" radius " ~ radius ~".");
|
||||
var x = int(lon*60/me.CELL_SIZE);
|
||||
var y = int(lat*60/me.CELL_SIZE);
|
||||
var r = int(2*radius/(me.CELL_SIZE*1852.0));
|
||||
# print("Dumping foam at " ~ lat ~", " ~ lon ~
|
||||
# ". Center (" ~ x ~ "," ~ y ~ ") radius " ~ r ~".");
|
||||
var result = { extinguished : 0, protected : 0, waste : 0 };
|
||||
for (var dx = -r; dx <= r; dx += 1) {
|
||||
for (var dy = -r; dy <= r; dy += 1) {
|
||||
var cell = me.get_cell(x + dx, y + dy);
|
||||
if (cell == nil) {
|
||||
# print(" (" ~ (x + dx) ~ ", " ~ (y + dy) ~ ")");
|
||||
cell = FireCell.new(x + dx, y + dy);
|
||||
me.set_cell(x + dx, y + dy,
|
||||
cell);
|
||||
|
@ -661,12 +731,12 @@ CAFire.load_event_log = func (filename, skip_ahead_until=-1) {
|
|||
if (!fgcommand("loadxml",
|
||||
props.Node.new({ filename : filename,
|
||||
targetnode : logbase }))) {
|
||||
printlog("warn", "Wildfire ... failed loading '" ~ filename ~ "'");
|
||||
printlog("alert", "Wildfire ... failed loading '" ~ filename ~ "'");
|
||||
return;
|
||||
}
|
||||
|
||||
# Fast forward the automaton from the first logged event to the current time.
|
||||
me.set_models_enabled(0);
|
||||
CAFireModels.set_models_enabled(0);
|
||||
var first = 1;
|
||||
var events = props.globals.getNode(logbase).getChildren("event");
|
||||
foreach (var event; events) {
|
||||
|
@ -720,14 +790,7 @@ CAFire.load_event_log = func (filename, skip_ahead_until=-1) {
|
|||
while (me.generation * me.GENERATION_DURATION < now)
|
||||
me.update();
|
||||
}
|
||||
me.set_models_enabled(getprop(models_enabled_pp));
|
||||
}
|
||||
############################################################
|
||||
CAFire.set_models_enabled = func(on=1) {
|
||||
me.models_enabled = on;
|
||||
# We should do a pass over all cells here to add/remove models.
|
||||
# For now I don't so only active cells will actually remove the
|
||||
# models. All models will be hidden by there select animations, though.
|
||||
CAFireModels.set_models_enabled(getprop(models_enabled_pp));
|
||||
}
|
||||
######################################################################
|
||||
# Internal operations
|
||||
|
|
Loading…
Reference in a new issue